日常做web或者工控相关的渗透测试,偶然的机会接了个微信小程序的项目,研究了一下
我是将微信装在了模拟器上,不需要模拟器也可以,方法有很多
不需要模拟器可直接设代理 burpsuite 抓包
我使用的是夜神模拟器配合 burpsuite 进行抓包,我的夜神模拟器内设系统Android 5.0的版本,版本老的话易于兼容,新的版本都是7.0以上,抓取 HTTPS 包需要配置一些东西,很麻烦,大家可以按照我的版本搭建。
接下来开始配置抓包环境
ipconfig查看一下我们本机的ip

在burpsuite添加上代理,端口可随意设置,无要求

打开夜神模拟器,在 WLAN 选择手动代理,并设置代理地址和代理端口,与 burpsuite 的设置对应

保存后,打开浏览器访问ip:port,我这里是192.168.201.96:8888,点击CA Certificate下载证书

由于我这边之前安装好了,详细说一下操作步骤吧
下载好证书后,打开文件管理器,在sdcard->Download目录中可以看到下载下来的证书

将cacert.der更名为cacert.cer,也就是将后缀改成cer,然后到手机设置->安全中,选择从 SD 卡安装


安装好了后,打开浏览器访问百度看看,burpsutie能抓包就说明环境配置成功了
反编译微信小程序代码包
在模拟器登录上微信,访问一个小程序,等到小程序全部加载完了后,就可以在模拟器中找到一个文件夹,里面便存放着小程序的代码包
打开文件管理器,在data/data/com.tencent.mm/MicroMsg会生成一个md5加密命名的文件夹(如果同时有多个文件夹不容易识别的情况,可以选择把MicroMsg文件夹所有内容删除掉,再去重新打开微信小程序,就会得到唯一一个MD5加密命名的文件夹啦,其实看一下文件创建时间就能知道是哪个了)

在该文件夹下的appbrand/pkg目录下找到.wxapkg后缀结尾的文件,其中只有几MB大小的就是刚刚打开的小程序的代码包了

点击勾选之后,来到根目录下的mnt/shared/App目录,打开右上角三个.的功能菜单选择粘贴选择项,将文件复制到该文件夹


这个文件夹是与你电脑本机的共享文件夹,点开电脑文件夹,打开文件夹“AppShare”,就能查看到这个代码包了


接下来将这个文件进行反编译得到源码
1、需要配置Nodejs环境(下载地址:https://nodejs.org/zh-cn/download)
2、下载反编译工具(下载地址:https://wwi.lanzouq.com/i4CM8zr395e)
3、大多数的小程序代码包会有加密,附上一个解码工具(下载地址:https://wwi.lanzouq.com/iPqZbzr3a2h)
简单讲一下配置nodejs环境:
根据自己电脑系统及位数选择,我这里选择windows64位.msi格式安装包,因为不想再配环境变量了,安装的时候默认自己配了

.msi和.zip格式区别:
.msi是Windows installer开发出来的程序安装文件,它可以让你安装,修改,卸载你所安装的程序。说白了.msi就是Windows installer的数据包,把所有和安装文件相关的内容封装在一个包里。
.zip是一个压缩包,解压之后即可,不需要安装
安装完成后,.msi格式的安装包已经将node.exe添加到系统环境变量path中,如果你下载的是.zip格式,因为没有安装过程,所以需要手动将node.exe所在目录添加到环境变量path中,查看系统变量验证

安装好后验证一下,打开CMD窗口输入node -v查看版本

接下来安装脚本运行环境,依次输入下列命令
npm install esprima -g
npm install css-tree -g
npm install cssbeautify -g
npm install vm2 -g
npm install uglify-es -g
npm install js-beautify -g
npm install escodegen -g

全部安装好了后,下面开始正式反编译了!
1、首先将之前获取的代码包解密,利用解密工具,很幸运的是,我访问的这个小程序代码包未加密

2、将下载好的反编译工具wxappUnpacker解压,打开文件夹,在该文件夹打开cmd

3、输入命令node wuWxapkg.js 代码包所在位置,回车即可开始反编译


结束后就可在代码包的位置出现一个同名的文件夹,该文件夹就是反编译成功的源码包啦

源码包拿到后,就可以很舒服的看js代码了
首先挨个js文件点开看,js编程很灵活,招架不住文件太多了,直接上工具!
代码审计工具大家应该都用过,我这里推荐我用的审计工具Fortify SCA ,审计速度快但误报不少,还算好用,界面简单明了
这里发现有很多地方存在硬编码加密密钥漏洞,任何有权访问代码的人都可以访问加密密钥。应用程序发布后,除非对程序进行修补,否则无法更改加密密钥。有权访问此信息的员工可以使用此信息闯入系统。如果攻击者可以访问应用程序的可执行文件,他们可以提取加密密钥值。危害还是很大的。

收获不多,但初探过程很有意思,大家可以试一试
其他类型漏洞案例
下面举例其他类型的漏洞审计案例,这里目的是为了说明小程序有哪些漏洞可以挖
反编译出来的源码泄露登录账号密码,这里是因为在 js 文件中写死了账号密码,只做了前端验证导致的漏洞,从下面贴的两个小程序源码中可以看到


在时间稍稍往前的小程序中,还经常会有泄露小程序secret的情况,简直就是把打开保险箱的密码放在你面前
仔细翻找 js 文件能找到不少未鉴权的 api 接口(可以着重注意配置文件,不少配置文件都会写上路由列表),例如该 api 返回大量用户敏感信息

测试未授权时,有一些小技巧:例如当在 GET 或者 POST 传参中有token等鉴权参数,例如
GET /api/GetUserInfo?id=xxx&token=xxxx HTTP/1.1
可以尝试将token参数的值置空或者删除token参数,往往能 bypass 鉴权,我已经遇见好多次这种情况了。举例一个案例:
该微信小程序可以注册用户,注册账号登录之后抓包,我的账号数据包如下
GET /wx/queryOrders?orderState=&serviceUid=&repairUid=6864&pageNum=1&pageSize=20&uid=6864&token=9938C366-XXXX-XXXX-XXXX-9C7709D8C9E8
当我尝试将uid参数改成其他用户时,返回权限不足,尝试将token删除
GET /wx/queryOrders?orderState=&serviceUid=&pageNum=1&pageSize=200&uid=2000

除此之外,测试一些参数,比如手机号,不知道该系统用户手机号时,可以试试像上面说的将其置空,往往运气好能碰上系统后端查询使用的模糊查询为空时返回所有信息,下面贴图的案例就是将手机号参数置空后,成功获取到账号详细信息

下面案例举例一个通过 Cookie 中的参数进行鉴权的漏洞,可以通过修改NetId中的值来遍历获取用户信息。此类漏洞的挖掘在鉴权处的源码,审计时可以着重审计其验证流程

当时也是依靠这个漏洞获取到 VPN 账号密码,得以进入内网渗透
使用 burpsuite 抓取管理员登录数据包,获取返回包

该处在login.js文件登录判断条件中,源码判断返回为 0 时登录成功,所以我们将返回包从 1 改成 0 即可登录成功。

还有 任意密码重置 ,该处漏洞倒也是在黑盒中无意发现,在修改密码处需要验证对应账号接收到的短信验证码。但怀着尝试的心态通过 buspsuite 抓包绕过 js 限制,随意填写验证码便可以重置任意用户密码,不细心就会很容易忽视的点

当时测试数据的时候,发现添加字符%%会导致其后端报错,返回appid和secret

获取到的appid和secret可以到微信的官方接口去自由生成微信小程序的命脉AccessToken

拿到 AccessToken,相当于可以控制整个小程序了,并且 AccessToken 微信每天只能生成20次,不断请求满20次的话可以使小程序崩溃无法使用。

个人感觉,微信小程序的渗透我觉得最重要的还是仔细审计一下反编译得到的源码,源码里才都是宝贝
很好奇,就使用rubyonrails自动化单元测试而言,你们正在做什么?您是否创建了一个脚本来在cron中运行rake作业并将结果邮寄给您?git中的预提交Hook?只是手动调用?我完全理解测试,但想知道在错误发生之前捕获错误的最佳实践是什么。让我们理所当然地认为测试本身是完美无缺的,并且可以正常工作。下一步是什么以确保他们在正确的时间将可能有害的结果传达给您? 最佳答案 不确定您到底想听什么,但是有几个级别的自动代码库控制:在处理某项功能时,您可以使用类似autotest的内容获得关于哪些有效,哪些无效的即时反馈。要确保您的提
我正在编写一个包含C扩展的gem。通常当我写一个gem时,我会遵循TDD的过程,我会写一个失败的规范,然后处理代码直到它通过,等等......在“ext/mygem/mygem.c”中我的C扩展和在gemspec的“扩展”中配置的有效extconf.rb,如何运行我的规范并仍然加载我的C扩展?当我更改C代码时,我需要采取哪些步骤来重新编译代码?这可能是个愚蠢的问题,但是从我的gem的开发源代码树中输入“bundleinstall”不会构建任何native扩展。当我手动运行rubyext/mygem/extconf.rb时,我确实得到了一个Makefile(在整个项目的根目录中),然后当
我有一个围绕一些对象的包装类,我想将这些对象用作散列中的键。包装对象和解包装对象应映射到相同的键。一个简单的例子是这样的:classAattr_reader:xdefinitialize(inner)@inner=innerenddefx;@inner.x;enddef==(other)@inner.x==other.xendenda=A.new(o)#oisjustanyobjectthatallowso.xb=A.new(o)h={a=>5}ph[a]#5ph[b]#nil,shouldbe5ph[o]#nil,shouldbe5我试过==、===、eq?并散列所有无济于事。
我有一些Ruby代码,如下所示:Something.createdo|x|x.foo=barend我想编写一个测试,它使用double代替block参数x,这样我就可以调用:x_double.should_receive(:foo).with("whatever").这可能吗? 最佳答案 specify'something'dox=doublex.should_receive(:foo=).with("whatever")Something.should_receive(:create).and_yield(x)#callthere
Sinatra新手;我正在运行一些rspec测试,但在日志中收到了一堆不需要的噪音。如何消除日志中过多的噪音?我仔细检查了环境是否设置为:test,这意味着记录器级别应设置为WARN而不是DEBUG。spec_helper:require"./app"require"sinatra"require"rspec"require"rack/test"require"database_cleaner"require"factory_girl"set:environment,:testFactoryGirl.definition_file_paths=%w{./factories./test/
我遵循MichaelHartl的“RubyonRails教程:学习Web开发”,并创建了检查用户名和电子邮件长度有效性的测试(名称最多50个字符,电子邮件最多255个字符)。test/helpers/application_helper_test.rb的内容是:require'test_helper'classApplicationHelperTest在运行bundleexecraketest时,所有测试都通过了,但我看到以下消息在最后被标记为错误:ERROR["test_full_title_helper",ApplicationHelperTest,1.820016791]test
我已经构建了一些serverspec代码来在多个主机上运行一组测试。问题是当任何测试失败时,测试会在当前主机停止。即使测试失败,我也希望它继续在所有主机上运行。Rakefile:namespace:specdotask:all=>hosts.map{|h|'spec:'+h.split('.')[0]}hosts.eachdo|host|begindesc"Runserverspecto#{host}"RSpec::Core::RakeTask.new(host)do|t|ENV['TARGET_HOST']=hostt.pattern="spec/cfengine3/*_spec.r
我在app/helpers/sessions_helper.rb中有一个帮助程序文件,其中包含一个方法my_preference,它返回当前登录用户的首选项。我想在集成测试中访问该方法。例如,这样我就可以在测试中使用getuser_path(my_preference)。在其他帖子中,我读到这可以通过在测试文件中包含requiresessions_helper来实现,但我仍然收到错误NameError:undefinedlocalvariableormethod'my_preference'.我做错了什么?require'test_helper'require'sessions_hel
只是想确保我理解了事情。据我目前收集到的信息,Cucumber只是一个“包装器”,或者是一种通过将事物分类为功能和步骤来组织测试的好方法,其中实际的单元测试处于步骤阶段。它允许您根据事物的工作方式组织您的测试。对吗? 最佳答案 有点。它是一种组织测试的方式,但不仅如此。它的行为就像最初的Rails集成测试一样,但更易于使用。这里最大的好处是您的session在整个Scenario中保持透明。关于Cucumber的另一件事是您(应该)从使用您的代码的浏览器或客户端的角度进行测试。如果您愿意,您可以使用步骤来构建对象和设置状态,但通常您
我有:When/^(?:|I)follow"([^"]*)"(?:within"([^"]*)")?$/do|link,selector|with_scope(selector)doclick_link(link)endend我打电话的地方:Background:GivenIamanexistingadminuserWhenIfollow"CLIENTS"我的HTML是这样的:CLIENTS我一直收到这个错误:.F-.F--U-----U(::)failedsteps(::)nolinkwithtitle,idortext'CLIENTS'found(Capybara::Element