0×00. 前言

一些防护SSRF漏洞的代码一般使用正则来判断访问IP是否为内部IP,比如下面这段网上比较常见的正则:

if re.match(r"^192\.168(\.([2][0-4]\d|[2][5][0-5]|[01]?\d?\d)){2}$", ip_address) or \
 
    re.match(r"^172\.([1][6-9]|[2]\d|3[01])(\.([2][0-4]\d|[2][5][0-5]|[01]?\d?\d)){2}$", ip_address) or \
    re.match(r"^10(\.([2][0-4]\d|[2][5][0-5]|[01]?\d?\d)){3}$", ip_address):
    raise Execption("inner ip") 

很明显这个正则有很多问题,可以有多种方式绕过,比如

1. 利用八进制IP地址绕过

2. 利用十六进制IP地址绕过

3. 利用十进制的IP地址绕过

4. 各种进制组合形成的IP绕过

一般我们常见都是10进制表示的IP,其实系统是可以识别其他进制表示的IP,比如8进制,16进制,或者它们的组合,更多详情可以参考:那些不为人知的IP

所以,我们在测试系统是否有SSRF漏洞的时候,有时候需要尝试各种进制的IP组合,看看是否能绕过系统的防护,于是就有了本文的这个小程序,用于自动生成各种进制形式的IP,以帮助我们进行安全测试

0×01. 正文

程序代码

#!/usr/bin/env python # -*- coding:utf8 -*- """
各种进制的IP表示及其它们的组合
""" import socket import struct import itertools def ip_split_by_comma_oct(ip):     """
    :param ip:
    :return:
    """     parsed_result = set()
    ip_split = str(ip).split('.')
    ip_split_oct = [oct(int(_)) for _ in ip_split]
    parsed_result.add('.'.join(ip_split_oct))
    return parsed_result def ip_split_by_comma_hex(ip):     """
    :param ip:
    :return:
    """     parsed_result = set()
    ip_split = str(ip).split('.')
    ip_split_hex = [hex(int(_)) for _ in ip_split]
    parsed_result.add('.'.join(ip_split_hex))
    return parsed_result def combination_oct_int_ip(ip):     """
    :param ip:
    :return:
    """     result = set()
    parsed_result = set()
    ip_split = str(ip).split('.')
    oct_2 = list(itertools.combinations([0, 1, 2, 3], 2))
    oct_3 = list(itertools.combinations([0, 1, 2, 3], 3))
    for n, _ in enumerate(ip_split):
        _tmp = oct(int(_))
        _delete = ip_split[:n] + ip_split[n+1:]
        _delete.insert(n, _tmp)
        result.add(tuple(_delete))
    for _ in oct_2:
        _tmp_ip = ip_split[:]
        _tmp1 = oct(int(ip_split[_[0]]))
        _tmp2 = oct(int(ip_split[_[1]]))
        del _tmp_ip[_[0]]
        del _tmp_ip[_[1] - 1]
        _tmp_ip.insert(_[0], _tmp1)
        _tmp_ip.insert(_[1], _tmp2)
        result.add(tuple(_tmp_ip))
    for _ in oct_3:
        _tmp_ip = ip_split[:]
        _tmp1 = oct(int(ip_split[_[0]]))
        _tmp2 = oct(int(ip_split[_[1]]))
        _tmp3 = oct(int(ip_split[_[2]]))
        del _tmp_ip[_[0]]
        del _tmp_ip[_[1] - 1]
        del _tmp_ip[_[2] - 2]
        _tmp_ip.insert(_[0], _tmp1)
        _tmp_ip.insert(_[1], _tmp2)
        _tmp_ip.insert(_[2], _tmp3)
        result.add(tuple(_tmp_ip))
    for _ in result:
        parsed_result.add('.'.join(_))
    return parsed_result def combination_hex_int_ip(ip):     """
    :param ip:
    :return:
    """     result = set()
    parsed_result = set()
    ip_split = str(ip).split('.')
    hex_2 = list(itertools.combinations([0, 1, 2, 3], 2))
    hex_3 = list(itertools.combinations([0, 1, 2, 3], 3))
    for n, _ in enumerate(ip_split):
        _tmp = hex(int(_))
        _delete = ip_split[:n] + ip_split[n+1:]
        _delete.insert(n, _tmp)
        result.add(tuple(_delete))
    for _ in hex_2:
        _tmp_ip = ip_split[:]
        _tmp1 = hex(int(ip_split[_[0]]))
        _tmp2 = hex(int(ip_split[_[1]]))
        del _tmp_ip[_[0]]
        del _tmp_ip[_[1] - 1]
        _tmp_ip.insert(_[0], _tmp1)
        _tmp_ip.insert(_[1], _tmp2)
        result.add(tuple(_tmp_ip))
    for _ in hex_3:
        _tmp_ip = ip_split[:]
        _tmp1 = hex(int(ip_split[_[0]]))
        _tmp2 = hex(int(ip_split[_[1]]))
        _tmp3 = hex(int(ip_split[_[2]]))
        del _tmp_ip[_[0]]
        del _tmp_ip[_[1] - 1]
        del _tmp_ip[_[2] - 2]
        _tmp_ip.insert(_[0], _tmp1)
        _tmp_ip.insert(_[1], _tmp2)
        _tmp_ip.insert(_[2], _tmp3)
        result.add(tuple(_tmp_ip))
    for _ in result:
        parsed_result.add('.'.join(_))
    return parsed_result def combination_hex_int_oct_ip(ip):     """
    :param ip:
    :return:
    """     result = set()
    parsed_result = set()
    ip_split = str(ip).split('.')
    hex_3 = list(itertools.combinations([0, 1, 2, 3], 3))
    for n1, n2, n3 in hex_3:
        _tmp_ip = ip_split[:]
        _tmp_2 = oct(int(_tmp_ip[n2]))
        _tmp_3 = hex(int(_tmp_ip[n3]))
        del _tmp_ip[n2]
        del _tmp_ip[n3 - 1]
        _tmp_ip.insert(n2, _tmp_2)
        _tmp_ip.insert(n3, _tmp_3)
        result.add(tuple(_tmp_ip))
    for _ in result:
        parsed_result.add('.'.join(_))
    return parsed_result if __name__ == '__main__':
    ip = '10.1.100.1'     ip_int = struct.unpack('!L', socket.inet_aton(ip))[0]
    ip_oct_no_comma = oct(ip_int)
    ip_hex_no_comma = hex(ip_int)
    ip_oct_by_comma = ip_split_by_comma_oct(ip)
    ip_hex_by_comma = ip_split_by_comma_hex(ip)
    all_result = ip_oct_by_comma | ip_hex_by_comma | combination_oct_int_ip(ip) | combination_hex_int_ip(ip) | combination_hex_int_oct_ip(ip)
    for _ip in all_result:
        print _ip 

代码很容易看懂,首先生成纯8进制表示的IP、纯16进制表示的IP,然后在分别生成10进制和8进制混合组成的IP,16进制和10进制混合组成的IP, 16进制8进制10进制混合组成的IP,最后输出各种组合的结果

在使用其他脚本或者工具遍历测试这个脚本的结果,看看是否能绕过SSRF的防护

部分截图:

比如生成10.1.100.1 这个IP的其他各种进制形式:

90.png

99.png

0×02. 总结

工具虽然简单,但却能给我们的渗透测试带来方便,其实工作中有很多可以总结沉淀的地方,都可以形成工具化,不仅能方便以后工作,还能有助于我们知识的沉淀,加快我们自身实力提升。也希望大家以后也能多多分享。

* 本文作者:knpewg85942