Skip to content

Instantly share code, notes, and snippets.

@eriknl
Last active October 4, 2024 08:57

Revisions

  1. eriknl revised this gist Nov 12, 2023. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion papi.py
    Original file line number Diff line number Diff line change
    @@ -2,7 +2,7 @@
    from struct import *

    """
    This implementation was reverse engineered using Wireshark (and source code), strace and two excelent articles:
    This implementation was reverse engineered using Wireshark (and source code), strace and two excellent articles:
    - https://x-c3ll.github.io/posts/CVE-2018-7081-RCE-ArubaOS/
    - https://packetstormsecurity.com/files/136997/Aruba-Authentication-Bypass-Insecure-Transport-Tons-Of-Issues.html
    """
  2. eriknl revised this gist Nov 12, 2023. 1 changed file with 6 additions and 0 deletions.
    6 changes: 6 additions & 0 deletions papi.py
    Original file line number Diff line number Diff line change
    @@ -61,6 +61,12 @@ def sxdr_write_u32(value):
    msg += pack('>I', value)
    return msg

    def sxdr_write_s32(value, sign):
    msg = b'\x06'
    msg += sxdr_write_bool(sign)
    msg += sxdr_write_u32(value)
    return msg

    def sxdr_write_bool(value):
    msg = b'\x07'
    if value:
  3. eriknl revised this gist Sep 19, 2022. 1 changed file with 4 additions and 46 deletions.
    50 changes: 4 additions & 46 deletions papi.py
    Original file line number Diff line number Diff line change
    @@ -41,49 +41,6 @@ def papi_header(dst_host, src_host, dst_port, src_port, sequence_number, message
    # End 0x4C
    return header

    def amapi_execute_command_object_body(parameters=[], object_type=0, op_type=0, app_id='', object_name='', major_ver=8, minor_ver=5):
    body = sxdr_write_str('executeCommandObject')
    body += sxdr_write_u8(0x00)
    body += sxdr_write_u8(0x00)
    body += sxdr_write_u16(object_type) # commandObj->objectType
    body += sxdr_write_u16(op_type) # commandObj->opType
    body += sxdr_write_str(app_id) # commandObj->appId
    body += sxdr_write_str(object_name) # commandObj->objectName
    body += sxdr_write_u8(major_ver) # commandObj->majorVer
    body += sxdr_write_u8(minor_ver) # commandObj->minorVer
    body += sxdr_write_str('') # commandObj->instance
    body += sxdr_write_bool(False) # commandObj->bIsLocalCommand
    body += sxdr_write_u16(0x00) # commandObj->commandStrLen
    body += sxdr_write_str('') # commandObj->commandStr
    body += sxdr_write_u16(0x00) # commandObj->commandLogStrLen
    body += sxdr_write_str('') # commandObj->commandLogStr
    body += sxdr_write_u16(0x00) # commandObj->rawDatalength
    body += sxdr_write_u16(0x00) # commandObj->secretLen
    body += sxdr_write_str('') # commandObj->secret ???
    body += sxdr_write_u8(0x00) # commandObj->encryptFlag
    body += sxdr_write_u32(len(parameters)) # numEntries
    for keyvalue in parameters:
    for key, value in keyvalue.items():
    body += sxdr_write_str(key) # key
    body += sxdr_write_str(value) # value
    body += sxdr_write_bool(False) # keyValue->wasMode
    body += sxdr_write_bool(False) # keyValue->is_inst_key
    body += sxdr_write_bool(False) # keyValue->is_reorder_key
    body += sxdr_write_u32(0x00) # numEntries
    body += sxdr_write_u8(0x00) # configEncrypt
    body += sxdr_write_u8(0x00) # commandObj->cliRequest
    body += sxdr_write_u8(0x00) # commandObj->webRequest
    body += sxdr_write_u8(0x00)
    body += sxdr_write_str('admin') # commandObj->userName
    body += sxdr_write_str('root') # commandObj->userRole
    body += sxdr_write_str('/sc/mynode') # node
    body += sxdr_write_bool(False) # commandObj->preserve_no
    body += sxdr_write_str('') # commandObj->scappcmd
    body += sxdr_write_str('') # commandObj->currModeName
    body += sxdr_write_u16(0x00) # commandObj->flags
    body += sxdr_write_str('') # commandObj->permlen
    return (14001, body)

    def sxdr_write_ip(str_ip):
    msg = b'\x05'
    msg += bytes(map(int, str_ip.split('.')))[::-1] #???
    @@ -133,7 +90,8 @@ def sxdr_write_ip_af(str_ip):
    msg += b'\x00'*20
    return msg

    def sxdr_write_struct(value):
    msg = b'\x0C'
    msg += value
    def sxdr_write_hex(value):
    msg = b'\x08'
    msg += pack('>H', len(value))
    msg += bytes(value, 'latin-1')
    return msg
  4. eriknl revised this gist Jun 6, 2022. 1 changed file with 48 additions and 0 deletions.
    48 changes: 48 additions & 0 deletions papi.py
    Original file line number Diff line number Diff line change
    @@ -41,6 +41,49 @@ def papi_header(dst_host, src_host, dst_port, src_port, sequence_number, message
    # End 0x4C
    return header

    def amapi_execute_command_object_body(parameters=[], object_type=0, op_type=0, app_id='', object_name='', major_ver=8, minor_ver=5):
    body = sxdr_write_str('executeCommandObject')
    body += sxdr_write_u8(0x00)
    body += sxdr_write_u8(0x00)
    body += sxdr_write_u16(object_type) # commandObj->objectType
    body += sxdr_write_u16(op_type) # commandObj->opType
    body += sxdr_write_str(app_id) # commandObj->appId
    body += sxdr_write_str(object_name) # commandObj->objectName
    body += sxdr_write_u8(major_ver) # commandObj->majorVer
    body += sxdr_write_u8(minor_ver) # commandObj->minorVer
    body += sxdr_write_str('') # commandObj->instance
    body += sxdr_write_bool(False) # commandObj->bIsLocalCommand
    body += sxdr_write_u16(0x00) # commandObj->commandStrLen
    body += sxdr_write_str('') # commandObj->commandStr
    body += sxdr_write_u16(0x00) # commandObj->commandLogStrLen
    body += sxdr_write_str('') # commandObj->commandLogStr
    body += sxdr_write_u16(0x00) # commandObj->rawDatalength
    body += sxdr_write_u16(0x00) # commandObj->secretLen
    body += sxdr_write_str('') # commandObj->secret ???
    body += sxdr_write_u8(0x00) # commandObj->encryptFlag
    body += sxdr_write_u32(len(parameters)) # numEntries
    for keyvalue in parameters:
    for key, value in keyvalue.items():
    body += sxdr_write_str(key) # key
    body += sxdr_write_str(value) # value
    body += sxdr_write_bool(False) # keyValue->wasMode
    body += sxdr_write_bool(False) # keyValue->is_inst_key
    body += sxdr_write_bool(False) # keyValue->is_reorder_key
    body += sxdr_write_u32(0x00) # numEntries
    body += sxdr_write_u8(0x00) # configEncrypt
    body += sxdr_write_u8(0x00) # commandObj->cliRequest
    body += sxdr_write_u8(0x00) # commandObj->webRequest
    body += sxdr_write_u8(0x00)
    body += sxdr_write_str('admin') # commandObj->userName
    body += sxdr_write_str('root') # commandObj->userRole
    body += sxdr_write_str('/sc/mynode') # node
    body += sxdr_write_bool(False) # commandObj->preserve_no
    body += sxdr_write_str('') # commandObj->scappcmd
    body += sxdr_write_str('') # commandObj->currModeName
    body += sxdr_write_u16(0x00) # commandObj->flags
    body += sxdr_write_str('') # commandObj->permlen
    return (14001, body)

    def sxdr_write_ip(str_ip):
    msg = b'\x05'
    msg += bytes(map(int, str_ip.split('.')))[::-1] #???
    @@ -88,4 +131,9 @@ def sxdr_write_ipv6(str_ip6):
    def sxdr_write_ip_af(str_ip):
    msg = b'\x0B'
    msg += b'\x00'*20
    return msg

    def sxdr_write_struct(value):
    msg = b'\x0C'
    msg += value
    return msg
  5. eriknl revised this gist Sep 3, 2021. 1 changed file with 0 additions and 1 deletion.
    1 change: 0 additions & 1 deletion papi.py
    Original file line number Diff line number Diff line change
    @@ -33,7 +33,6 @@ def papi_header(dst_host, src_host, dst_port, src_port, sequence_number, message
    m = hashlib.md5()
    m.update(header + checksum + padding + body)
    key = b'asdf;lkj763'
    # key = b'aaaaaaaaaa'
    key = b'eG3eAUwZ5UEen1xu' # 'enhanced security'
    m.update(key)
    checksum = m.digest() # Calculated checksum
  6. eriknl revised this gist Aug 31, 2021. 1 changed file with 4 additions and 2 deletions.
    6 changes: 4 additions & 2 deletions papi.py
    Original file line number Diff line number Diff line change
    @@ -13,13 +13,13 @@ def papi_encrypt(data):
    decrypted += chr(c ^ 0x93)
    return bytes(decrypted, 'latin-1')

    def papi_header(dst_host, src_host, dst_port, src_port, sequence_number, message_code, body, calculate_checksum):
    def papi_header(dst_host, src_host, dst_port, src_port, sequence_number, message_code, body, calculate_checksum, natport=0):
    # Description Offset
    header = b'\x49\x72' # Magic Header for PAPI message 0x00
    header += b'\x00\x03' # Protocol Version ??? I have observed values 1 and 3 0x02
    header += bytes(map(int, dst_host.split('.'))) # Destination host 0x04
    header += bytes(map(int, src_host.split('.'))) # Source host 0x08
    header += b'\x00\x00' # NAT Port number 0x0C
    header += pack('>H', natport) # NAT Port number 0x0C
    header += b'\x00\x00' # "garbage" 0x0E
    header += pack('>H', dst_port) # Destination port 0x10
    header += pack('>H', src_port) # Source port 0x12
    @@ -33,6 +33,8 @@ def papi_header(dst_host, src_host, dst_port, src_port, sequence_number, message
    m = hashlib.md5()
    m.update(header + checksum + padding + body)
    key = b'asdf;lkj763'
    # key = b'aaaaaaaaaa'
    key = b'eG3eAUwZ5UEen1xu' # 'enhanced security'
    m.update(key)
    checksum = m.digest() # Calculated checksum
    header += checksum # Checksum 0x1C
  7. eriknl revised this gist Jul 5, 2020. 1 changed file with 5 additions and 0 deletions.
    5 changes: 5 additions & 0 deletions papi.py
    Original file line number Diff line number Diff line change
    @@ -82,4 +82,9 @@ def sxdr_write_mac(value):
    def sxdr_write_ipv6(str_ip6):
    msg = b'\x0A'
    msg += b'\x00'*16
    return msg

    def sxdr_write_ip_af(str_ip):
    msg = b'\x0B'
    msg += b'\x00'*20
    return msg
  8. eriknl revised this gist Jun 30, 2020. 1 changed file with 18 additions and 21 deletions.
    39 changes: 18 additions & 21 deletions papi.py
    Original file line number Diff line number Diff line change
    @@ -14,28 +14,30 @@ def papi_encrypt(data):
    return bytes(decrypted, 'latin-1')

    def papi_header(dst_host, src_host, dst_port, src_port, sequence_number, message_code, body, calculate_checksum):
    header = b'\x49\x72' # Magic Header for PAPI message 0x00
    header += b'\x00\x03' # Protocol Version ??? I have observed values 1 and 3 0x02
    header += bytes(map(int, dst_host.split('.'))) # Destination host 0x04
    header += bytes(map(int, src_host.split('.'))) # Source host 0x08
    header += b'\x00\x00' # NAT Port number 0x0c
    header += b'\x00\x00' # "garbage" 0x0e
    header += pack('>H', dst_port) # Destination port 0x10
    header += pack('>H', src_port) # Source port 0x12
    header += b'\x20\x04' # Packet type ??? 0x14
    header += b'\x00\x00' # Packet size ??? Seems unused in version 3 0x16
    header += pack('>H', sequence_number) # sequence_number 0x18
    header += pack('>H', message_code) # PAPI message code - application specific 0x1a
    # Description Offset
    header = b'\x49\x72' # Magic Header for PAPI message 0x00
    header += b'\x00\x03' # Protocol Version ??? I have observed values 1 and 3 0x02
    header += bytes(map(int, dst_host.split('.'))) # Destination host 0x04
    header += bytes(map(int, src_host.split('.'))) # Source host 0x08
    header += b'\x00\x00' # NAT Port number 0x0C
    header += b'\x00\x00' # "garbage" 0x0E
    header += pack('>H', dst_port) # Destination port 0x10
    header += pack('>H', src_port) # Source port 0x12
    header += b'\x20\x04' # Packet type ??? 0x14
    header += b'\x00\x00' # Packet size ??? Seems unused in version 3 0x16
    header += pack('>H', sequence_number) # sequence_number 0x18
    header += pack('>H', message_code) # PAPI message code - application specific 0x1A
    checksum = b'\x00'*16 # Empty checksum
    padding = b'\x00'*32 # Header padding
    padding = b'\x00'*32
    if calculate_checksum:
    m = hashlib.md5()
    m.update(header + checksum + padding + body)
    key = b'asdf;lkj763'
    m.update(key)
    checksum = m.digest() # Calculated checksum
    header += checksum
    header += padding
    header += checksum # Checksum 0x1C
    header += padding # Header padding 0x2C
    # End 0x4C
    return header

    def sxdr_write_ip(str_ip):
    @@ -58,11 +60,6 @@ def sxdr_write_u32(value):
    msg += pack('>I', value)
    return msg

    def sxdr_write_u64(value):
    msg = b'\x09'
    msg += pack('>Q', value)
    return msg

    def sxdr_write_bool(value):
    msg = b'\x07'
    if value:
    @@ -85,4 +82,4 @@ def sxdr_write_mac(value):
    def sxdr_write_ipv6(str_ip6):
    msg = b'\x0A'
    msg += b'\x00'*16
    return msg
    return msg
  9. eriknl revised this gist Jun 30, 2020. 1 changed file with 5 additions and 0 deletions.
    5 changes: 5 additions & 0 deletions papi.py
    Original file line number Diff line number Diff line change
    @@ -81,3 +81,8 @@ def sxdr_write_mac(value):
    msg = b'\x01'
    msg += bytes.fromhex(value.replace(':', ''))
    return msg

    def sxdr_write_ipv6(str_ip6):
    msg = b'\x0A'
    msg += b'\x00'*16
    return msg
  10. eriknl revised this gist Oct 21, 2019. 1 changed file with 18 additions and 13 deletions.
    31 changes: 18 additions & 13 deletions papi.py
    Original file line number Diff line number Diff line change
    @@ -14,18 +14,18 @@ def papi_encrypt(data):
    return bytes(decrypted, 'latin-1')

    def papi_header(dst_host, src_host, dst_port, src_port, sequence_number, message_code, body, calculate_checksum):
    header = b'\x49\x72' # Magic Header for PAPI message
    header += b'\x00\x03' # Protocol Version ??? I have observed values 1 and 3
    header += bytes(map(int, dst_host.split('.'))) # Destination host
    header += bytes(map(int, src_host.split('.'))) # Source host
    header += b'\x00\x00' # NAT Port number
    header += b'\x00\x00' # "garbage"
    header += pack('>H', dst_port) # Destination port
    header += pack('>H', src_port) # Source port
    header += b'\x20\x04' # Packet type ???
    header += b'\x00\x00' # Packet size ??? Seems unused in version 3
    header += pack('>H', sequence_number) # sequence_number
    header += pack('>H', message_code) # PAPI message code - application specific
    header = b'\x49\x72' # Magic Header for PAPI message 0x00
    header += b'\x00\x03' # Protocol Version ??? I have observed values 1 and 3 0x02
    header += bytes(map(int, dst_host.split('.'))) # Destination host 0x04
    header += bytes(map(int, src_host.split('.'))) # Source host 0x08
    header += b'\x00\x00' # NAT Port number 0x0c
    header += b'\x00\x00' # "garbage" 0x0e
    header += pack('>H', dst_port) # Destination port 0x10
    header += pack('>H', src_port) # Source port 0x12
    header += b'\x20\x04' # Packet type ??? 0x14
    header += b'\x00\x00' # Packet size ??? Seems unused in version 3 0x16
    header += pack('>H', sequence_number) # sequence_number 0x18
    header += pack('>H', message_code) # PAPI message code - application specific 0x1a
    checksum = b'\x00'*16 # Empty checksum
    padding = b'\x00'*32 # Header padding
    if calculate_checksum:
    @@ -58,6 +58,11 @@ def sxdr_write_u32(value):
    msg += pack('>I', value)
    return msg

    def sxdr_write_u64(value):
    msg = b'\x09'
    msg += pack('>Q', value)
    return msg

    def sxdr_write_bool(value):
    msg = b'\x07'
    if value:
    @@ -75,4 +80,4 @@ def sxdr_write_str(value):
    def sxdr_write_mac(value):
    msg = b'\x01'
    msg += bytes.fromhex(value.replace(':', ''))
    return msg
    return msg
  11. eriknl revised this gist Oct 11, 2019. 1 changed file with 5 additions and 1 deletion.
    6 changes: 5 additions & 1 deletion papi.py
    Original file line number Diff line number Diff line change
    @@ -2,7 +2,7 @@
    from struct import *

    """
    This implementation was reverse engineered using Wireshark (and source code), strace and two excellent articles:
    This implementation was reverse engineered using Wireshark (and source code), strace and two excelent articles:
    - https://x-c3ll.github.io/posts/CVE-2018-7081-RCE-ArubaOS/
    - https://packetstormsecurity.com/files/136997/Aruba-Authentication-Bypass-Insecure-Transport-Tons-Of-Issues.html
    """
    @@ -72,3 +72,7 @@ def sxdr_write_str(value):
    msg += bytes(value, 'latin-1')
    return msg

    def sxdr_write_mac(value):
    msg = b'\x01'
    msg += bytes.fromhex(value.replace(':', ''))
    return msg
  12. eriknl revised this gist Sep 26, 2019. 1 changed file with 0 additions and 5 deletions.
    5 changes: 0 additions & 5 deletions papi.py
    Original file line number Diff line number Diff line change
    @@ -72,8 +72,3 @@ def sxdr_write_str(value):
    msg += bytes(value, 'latin-1')
    return msg

    def sxdr_write_str2(value):
    msg = b'\x00'
    msg += pack('B', len(value))
    msg += bytes(value, 'latin-1')
    return msg
  13. eriknl revised this gist Sep 25, 2019. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion papi.py
    Original file line number Diff line number Diff line change
    @@ -2,7 +2,7 @@
    from struct import *

    """
    This implementation was reverse engineered using Wireshark (and source code), strace and two excelent articles:
    This implementation was reverse engineered using Wireshark (and source code), strace and two excellent articles:
    - https://x-c3ll.github.io/posts/CVE-2018-7081-RCE-ArubaOS/
    - https://packetstormsecurity.com/files/136997/Aruba-Authentication-Bypass-Insecure-Transport-Tons-Of-Issues.html
    """
  14. eriknl created this gist Sep 23, 2019.
    79 changes: 79 additions & 0 deletions papi.py
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,79 @@
    import hashlib
    from struct import *

    """
    This implementation was reverse engineered using Wireshark (and source code), strace and two excelent articles:
    - https://x-c3ll.github.io/posts/CVE-2018-7081-RCE-ArubaOS/
    - https://packetstormsecurity.com/files/136997/Aruba-Authentication-Bypass-Insecure-Transport-Tons-Of-Issues.html
    """

    def papi_encrypt(data):
    decrypted = ''
    for c in data:
    decrypted += chr(c ^ 0x93)
    return bytes(decrypted, 'latin-1')

    def papi_header(dst_host, src_host, dst_port, src_port, sequence_number, message_code, body, calculate_checksum):
    header = b'\x49\x72' # Magic Header for PAPI message
    header += b'\x00\x03' # Protocol Version ??? I have observed values 1 and 3
    header += bytes(map(int, dst_host.split('.'))) # Destination host
    header += bytes(map(int, src_host.split('.'))) # Source host
    header += b'\x00\x00' # NAT Port number
    header += b'\x00\x00' # "garbage"
    header += pack('>H', dst_port) # Destination port
    header += pack('>H', src_port) # Source port
    header += b'\x20\x04' # Packet type ???
    header += b'\x00\x00' # Packet size ??? Seems unused in version 3
    header += pack('>H', sequence_number) # sequence_number
    header += pack('>H', message_code) # PAPI message code - application specific
    checksum = b'\x00'*16 # Empty checksum
    padding = b'\x00'*32 # Header padding
    if calculate_checksum:
    m = hashlib.md5()
    m.update(header + checksum + padding + body)
    key = b'asdf;lkj763'
    m.update(key)
    checksum = m.digest() # Calculated checksum
    header += checksum
    header += padding
    return header

    def sxdr_write_ip(str_ip):
    msg = b'\x05'
    msg += bytes(map(int, str_ip.split('.')))[::-1] #???
    return msg

    def sxdr_write_u8(value):
    msg = b'\x02'
    msg += pack('B', value)
    return msg

    def sxdr_write_u16(value):
    msg = b'\x03'
    msg += pack('>H', value)
    return msg

    def sxdr_write_u32(value):
    msg = b'\x04'
    msg += pack('>I', value)
    return msg

    def sxdr_write_bool(value):
    msg = b'\x07'
    if value:
    msg += sxdr_write_u8(1)
    else:
    msg += sxdr_write_u8(0)
    return msg

    def sxdr_write_str(value):
    msg = b'\x00'
    msg += pack('>H', len(value))
    msg += bytes(value, 'latin-1')
    return msg

    def sxdr_write_str2(value):
    msg = b'\x00'
    msg += pack('B', len(value))
    msg += bytes(value, 'latin-1')
    return msg