楔子
前两天的强网杯,有个题目叫高明的黑客,核心任务就是从3000多个php文件中找到存活的webshell,大概每个php文件有几十个post,get的点,头天晚上跑了一晚上,自己太菜了,很多东西忘了考虑,结束后拿多线程跑了一下很快就出来了,所以记录一下教训吧,碰到需要大量人力,时间的脚本,应该先尽量优化,而不是跑了半天发现很慢再来改快一点,以此循环,黄花菜都凉了,果然犹豫就会败北
一、python3多线程
1.1、Python3 线程中常用的两个模块为:
- _thread
- threading
1.2、thread 模块已被废弃。用户可以使用 threading 模块代替。所以,在 Python3 中不能再使用”thread” 模块。为了兼容性,Python3 将 thread 重命名为 “_thread”。使用起来也很简单
1 | _thread.start_new_thread ( function, args[, kwargs] ) |
一个实例
1 | import _thread |
1.3、_thread 提供了低级别的、原始的线程以及一个简单的锁,它相比于 threading 模块的功能还是比较有限的。
Thread类提供了以下方法:
- threading.currentThread(): 返回当前的线程变量。
- threading.enumerate(): 返回一个包含正在运行的线程的list
- threading.activeCount(): 返回正在运行的线程数量,与len(threading.enumerate())有相同的结果。
除了使用方法外,线程模块同样提供了Thread类来处理线程,Thread类提供了以下方法:
- run(): 用以表示线程活动的方法。
- start():启动线程活动。
join([time]):等待至线程中止。这阻塞调用线程直至线程的join() 方法被调用中止-正常退出或者抛出未处理的异常-或者是可选的超时发生。- isAlive(): 返回线程是否活动的。
- getName(): 返回线程名。
- setName(): 设置线程名。
1.4、最普通的使用多线程的方法
1 | import threading |
1.5、使用join,和queue
1 | import threading |
返回结果
1 | [[1, 4, 9], [9, 16, 25], [16, 16, 16], [25, 25, 25]] |
1.6、如果要使用线程同步
如果多个线程共同对某个数据修改,则可能出现不可预料的结果,为了保证数据的正确性,需要对多个线程进行同步。
使用 Thread 对象的 Lock 和 Rlock 可以实现简单的线程同步,这两个对象都有 acquire 方法和 release 方法,对于那些需要每次只允许一个线程操作的数据,可以将其操作放到 acquire 和 release 方法之间。如下
1 | import threading |
二、php webshell相关知识
WebShell就是以asp、php、jsp或者cgi等网页文件形式存在的一种命令执行环境,也可以将其称做为一种网页后门。
执行命令常用的函数有:
1 | system('命令') |
其他一些骚函数导致的php webshell
str_replace字符替换函数:
1 |
|
create_fuction()创建匿名函数:
1 |
|
总结:
- 系统命令执行: system, passthru, shell_exec, exec, popen, proc_open
- 代码执行: eval, assert, call_user_func,base64_decode, gzinflate, gzuncompress, gzdecode, str_rot13
- 文件包含: require, require_once, include, include_once, file_get_contents, file_put_contents, fputs, fwrite
三、暴力检验webshell存活
回到本题,最开始不知道有这么多post,get点,所以拿D盾等工具,23333,所有文件全部被找到了,我估计这些工具就是单纯匹配这几个敏感函数和post,get点,为了确认是否存活我们需要在本地搭建这个服务,并且找到通用的回显来确定,因为我在windows上环境搭建的php code可以用phpinfo()或者system('hostname');前者更大所以倾向于后者,命令用hostname能拿到主机名称,反过来是不行的,(如果你用Linux服务器使用system(‘id’)能检验phpcode,id检验命令,

所以初期代码为(暂时只考虑了get请求的参数
1 | import os |
想了想有没有优化的地方,如果能找到一个phpcode和命令都能测试的一个通用函数就可以减少一半的网络请求,只要你找肯定是有的那就是echo 'Hello Kitty';我们会发现无论是phpcode还是system执行了就会有Hello Kitty的回显
所以get请求就可以修改为
1 | def get_rep(filename, name): |
四、多线程检验webshell存活
现在只需要把上面的暴力脚本和多线程脚本结合一下
1 | import threading |
优化了一波,减少了多线程,但是递归文件查找,还有assert的改进
1 | import threading |