0x01 Challenge Description

Challenge: a substation uses IEC 61850 to collect data between the station and bay layers. Analyze the network capture, understand MMS, and find the hidden flag.
File: question_1531222544_JYvFGmLP49PFC0R2.pcap.zip; download from the Baidu Cloud link below.
0x02 Background
MMS, the Manufacturing Message Specification, is an industrial-control communication protocol defined by ISO/IEC 9506.
This article does not cover MMS in full; it only introduces the packet structures needed here.
For more detail, see the MMS article linked through Baidu Cloud at the end.
1、Initiate
MMSPdu Received ::=
A8 25 80 02 08 00 81 01 05 82 01 05 83 01 05 A4 16 80 01 01 81 03 05 F8 00 82 0C 03 EE 19 00 18 00 02 00 00 00 FD 18
Tag Length Value -- Tag definition
--------------------------------------------------------------------------------------------------
[8] A8 25 -- initiate-RequestPDU,
A8 = 1010 1000;
bit7,6 = Tag type, 00 = Universal tag, 10 = Context specific
bit5 = , 0 = Primitive, 1 = Contructed
(
00 0 = INTEGER, BITSTRING, BOOLEAN
00 1 = SEQUENCE, SEQUENCE OF
10 0 = IMPLICIT
10 1 = IMPLICIT SEQUENCE, IMPLICIT SEQUENCE OF
)
bit4-0 = Value, for primitive Universal tags, value defined in ASN.1, other use [x] in MMS.
{
[0] 80 02 08 00 - localDetailCalling (maxProposedMMSPduSize) = 2048 bytes
[1] 81 01 05 -- proposedMaxServOutstandingCalling
[2] 82 01 05 -- proposedMaxServOutstandingCalled
[3] 83 01 05 -- proposedDataStructureNestingLevel
[4] A4 16 -- mmsInitRequestDetail
{
[0] 80 01 01 -- proposedVersionNumber, MMS ISO IS 9506
[1] 81 03 05 F8 00 -- proposedParameterCBB,
BitString(11 bits used)
05 = indicate number of unused bit
F8 00
{
str1 (bit 0 / array support / MSB of F8) -- supported
str2 (bit 1 / structure support) -- supported
vnam (bit 2 / named variable support) -- supported
valt(bit 3 /alternate access support) -- supported
vadr(bit 4/ unnamed variable support) -- supported
viscera(bit 5/ scattered access support) -- not-supported
toy(bit 6/ third party operations support) -- not-supported
villas(bit 7/ named variable list support) -- not-supported
real(bit 8 / ASN.1 real data type support) -- not-supported
ache(bit 9/ acknowledge event conditionsupport) -- not-supported
chi(bit 10 / condition event support) -- not-supported
}
[2] 82 0C 03 EE 19 00 18 00 02 00 00 00 FD 18 -- servicesSupportedCalling, see ISO/IEC-9506
}
}
2、Initiate-Response
MMSPdu Received ::=
A9 25 80 02 08 00 81 01 05 82 01 05 83 01 05 A416 80 01 01 81 03 05 F8 00 82 0C 03 EE 19 00 18 00 02 00 00 00 FD 18
[9] A9 25 -- Initiate-ResponsePDU
{
[0] 80 02 08 00 -- localDetailCalled
[1] 81 01 05 -- negotiatedMaxServOutstandingCalling
[2] 82 01 05 -- negotiatedMaxServOutstandingCalled
[3] 83 01 05 -- negotiatedDataStructureNestingLevel
[4] A4 16
{
[0] 80 01 01 -- negotiatedVersionNumber
[1] 81 03 05 F8 00 -- negotiatedParameterCBB
[2] 82 0C 03 EE 19 00 18 00 02 00 00 00 FD 18 -- servicesSupportedCalled
}
}
3、Identify
MMSPdu Received ::=
A0 05 02 01 01 82 00
[0] A0 05 -- Confirmed-RequestPDU
{
02 01 01 -- invokeID
( 02 = 000 0 0010, Universal Primitive tag, Tag Value = 2 = Integer. )
[2] 82 00 -- ConfirmedServiceRequest, 82 = Request identify
}
where, invokeID ::=01
4、Identify-Response
MMSPdu Received ::=
A1 2A 02 01 01 A2 25 80 0B 53 49 53 43 4F 2C 2049 6E 63 2E 81 10 41 58 53 34 2D 4D 4D 53 2D 3133 32 2D 30 31 38 82 04 32 2E 30 30
[1] A1 2A -- Confirmed-ResponsePDU
{
02 01 01 -- invokeID, Integer
[2] A2 25 -- ConfirmedServiceResponse, A2 = Response identify.
{
[0] 80 0B 53 49 53 43 4F 2C 20 49 6E 63 2E -- vendorName
[1] 81 10 41 58 53 34 2D 4D 4D 53 2D 31 33 32 2D 30 31 38 -- modelName
[2] 82 04 32 2E 30 30 -- revision
}
}
where,
invokeID::=01 note: matching of response to is done by matching invokeID with response invokeID.
vendorName::="SISCO, Inc"
modelName::="AXS4-MMS-132-018"
revision::="2.00"
check [MMS and ASN.1 Encoding] page 10.
5、Read-Request
MMSPdu Received ::=
A0 1E 02 01 0A A4 19 A1 17 A0 15 30 13 A0 11 80 0F 66 65 65 64 65 72 31 5F 33 5F 70 68 61 73 65
[0] A0 1E -- ConfirmedRequestPDU
{
02 01 0A -- invokeID
[4] A4 19 -- ConfirmedServiceRequest, A4 = Read
{
[1] A1 17 -- variableAccessSpecification
{
[0] 30 13 -- listOfVariable
(30 = 00 1 10000, Universal Constructed)
{
[0] A0 11 -- variableSpecification
{
[0] 80 0F 66 65 65 64 65 72 31 5f 33 5f 70 68 61 73 65 -- name
}
}
}
}
}
where,
invokeID::=0A
Identifier (name of variable to read)::="feeder1_3_phase"
6、Read -Response
Assume
typedef struct var_def
{
int a;
int b;
} VAR_DEF;
VAR_DEF feeder1_3_phase;
MMS Data Production
Data ::= CHOICE
{
[1] IMPLICIT SEQUENCE OF,-- arrayed data
[2] IMPLICIT SEQUENCE OF,-- structured data
[3] IMPLICIT BOOLEAN,
[4] IMPLICIT BIT STRING,
[5] IMPLICIT INTEGER,-- signed int
[6] IMPLICIT INTEGER,-- unsigned int
[7] IMPLICIT Floating Point,
[9] IMPLICIT OCTET STRING,
[10] IMPLICIT VisibleString,
[11] IMPLICIT GeneralizedTime,
[12] IMPLICIT TimeofDay,
[13] IMPLICIT INTEGER,-- BCD
[14] IMPLICIT BIT STRING,-- boolean array
[15] IMPLICIT OBJECT IDENTIFIER
}
The encoded structure of the encoded data can be determined via VAR_DEF
VAR_DEF::= TAG
-------------------------------------------
struct { A2
inta; 85
intb; 85
}
MMSPdu Received ::=
A1 0F 02 01 0A A4 0A A1 08 A2 06 85 01 00 85 0100
[1] A1 0F -- ConfirmedResponsePDU
{
02 01 0A -- invokeID
[4] A4 0A -- ConfirmedServiceResponse, A4 = Read
{
[1] OF A1 08 -- listOfAccessResult
{
A2 06 -- success, Data of struct
{
85 01 00 -- int a;
85 01 00 -- int b;
}
}
}
}
where,
invokeID::=0A
value of a::=00, value of b::=00
Three MMS packet types are shown here.
Analyzing these three packet types reveals several MMS protocol structures:
Initiate
initiate-RequestPDU contains:
- localDetailCalling
- proposedMaxServOutstandingCalling
- proposedMaxServOutstandingCalled
- proposedDataStructureNestingLevel
- mmsInitRequestDetail
- proposedVersionNumber
- proposedParameterCBB
- servicesSupportedCalling and related information
Initiate-ResponsePDU contains:
- localDetailCalled
- negotiatedMaxServOutstandingCalling
- negotiatedMaxServOutstandingCalled
- negotiatedDataStructureNestingLevel
- negotiatedVersionNumber
- negotiatedParameterCBB
- servicesSupportedCalled and related information
Identify:
Confirmed-RequestPDU contains:
- invokeID
- tag
- ConfirmedServiceRequest and related information
Confirmed-ResponsePDU contains:
- invokeID
- ConfirmedServiceResponse
- vendorName
- modelName
- revision and related information
Read:
ConfirmedRequestPDU contains:
- invokeID
- ConfirmedServiceRequest
- variableAccessSpecification
- listOfVariable
- variableSpecification
- name and related information
ConfirmedResponsePDU contains:
- invokeID
- ConfirmedServiceResponse
- listOfAccessResult and related information
This is only a simplified explanation. The three packet types above do not cover every MMS protocol data unit or structure.
For deeper study, download GBT16720.2-2005, Industrial Automation Systems—Manufacturing Message Specification, Part 2: Protocol Specification, from the Baidu Cloud link below.
0x03 Solution
For a packet-analysis CTF challenge, the first step is to search for the keyword 'flag'.

Searching for keywords finds flag.txt. Search again for that value near
1771 146.535714 192.168.2.112 192.168.2.53 MMS 110 513 confirmed-RequestPDU
This reveals:

The packet above is a RequestPDU with this request content:
MMS
confirmed-RequestPDU
invokeID: 513
confirmedServiceRequest: fileOpen (72)
fileOpen
fileName: 1 item
FileName item: flag.txt
initialPosition: 0
This corresponds to the RequestPDU structure.
The corresponding ResponsePDU must exist.
The data we need is not the fileOpen (72) stream.
fileOpen tells us only the name of the file being opened.
The file list contains flag.txt, and the operation we need is fileRead or fileWrite.
The flag.txt entry is at line 1771, so filter for the ResponsePDU of fileRead or fileWrite.
The flag should appear within the following records after line 1771.
Since fileOpen is 72, one might expect 73 to be fileRead, 74 fileWrite, and 75 fileClose. However:



73 is indeed fileRead, but 74 is fileClose and 75 returns empty content, confirming that no write operation exists.
Apply the filter mms.confirmedServiceRequest == 73 and search after line 1771 for fileData from a read of flag.txt.

After line 1771, the nearest relevant entry is line 1800, a RequestPDU. Locate the matching ResponsePDU with invokeID 527:

The fileData value is 363138353040313032.
The corresponding ASCII text is 61850@102.
This is the final flag.
0x04 Conclusion
The elegant solution requires only the structures of Confirmed-RequestPDU and Confirmed-ResponsePDU in MMS. Find the matching service and solve it with a short script:
import pyshark
def flag():
try:
captures = pyshark.FileCapture("question_1531222544_JYvFGmLP49PFC0R2.pcap")
flag_frsm = False
flag_frsm_id = None
flag_read = False
for capture in captures:
for pkt in capture:
if pkt.layer_name == "mms":
# file open
if hasattr(pkt, "confirmedservicerequest") and int(pkt.confirmedservicerequest) == 72:
if hasattr(pkt, "filename_item"):
filename_items = pkt.filename_item.fields
for f in filename_items:
file_name = str(f.get_default_value())
if file_name == "flag.txt":
flag_frsm = True
if hasattr(pkt, "confirmedserviceresponse") and int(pkt.confirmedserviceresponse) == 72 and flag_frsm:
# print(pkt.field_names)
if hasattr(pkt, "frsmid"):
flag_frsm_id = pkt.frsmid
flag_frsm = False
# file read
if hasattr(pkt, "confirmedservicerequest") and int(pkt.confirmedservicerequest) == 73 and flag_frsm_id:
if hasattr(pkt, "fileread"):
if str(pkt.fileread) == str(flag_frsm_id):
flag_read = True
flag_frsm_id = None
if hasattr(pkt, "confirmedserviceresponse") and int(pkt.confirmedserviceresponse) == 73 and flag_read:
if hasattr(pkt, "filedata"):
data = str(pkt.filedata).replace(":", "")
print(hex_to_ascii(data))
flag_read = False
except Exception as e:
print(e)
def hex_to_ascii(data):
data = data.decode("hex")
flags = []
for d in data:
_ord = ord(d)
if (_ord > 0) and (_ord < 128):
flags.append(chr(_ord))
return ''.join(flags)
if __name__ == '__main__':
flag()
Representative industrial protocols include MMS, Modbus, DNP3, MELSEC-Q, S7, and EtherNet/IP.
Challenges can be designed in many ways, but familiarity with the protocol makes them much easier to solve.
I had only just begun studying ICS security, so corrections are welcome. Anyone interested is also welcome to study ICS security together.
0x04 References
===================== Links:
Link:https://pan.baidu.com/s/1wI_1fErCAvvQIF_DYPIOiQ Password: 9mb8