다음 사례는 ISO 21434가 실제로 어떻게 단계적으로 적용되는지 보여준다. 사례 연구는 첨단 운전자 지원 시스템 (Advanced Driver Assistance Systems, ADAS) 프로젝트에서 가져온 것으로 기사의 형식에 맞게 단순화하였다.
1단계: 아이템 정의 아이템 정의는 구성 요소의 범위를 정의하기 위해 필요하다. 정의된 범위는 시스템의 자산을 식별하기 위한 참조로 사용된다. 이 예에서 아이템은 넓은 의미에서 전체 ADAS 시스템을 말한다. 최상위 네트워크 아키텍처는그림 3과 같으며, CAN 프로토콜을 통해 모든 통신이 이루어진다고 가정한다. 외부 인터페이스는 기본 아키텍처를 기반으로 식별된다. 이 시스템은 4G 네트워크를 통해 OEM 클라우드 인프라와 통신할 수 있는 기능이 있으며 게이트웨이 모듈에 연결된 OBD 단자가 있다.
그림 3 | ADAS 네트워크 아키텍처의 예
2단계: 자산 식별 다음 단계는 아이템 범위에 속한 모든 자산을 나열하는 것이다. 자산은 예를 들어 기능 안전 목표, 재정적 위험, 운영 비용 및 개인 정보 보호와 같이 손상될 때의 위험 또는 가치를 기반으로 선택된다. 다음은 ADAS 시스템의 자산(Asset, A) 예이다.
- A1:ADAS가 송수신하는 네트워크 메시지 - A2:안전 메커니즘을 포함한 ADAS 소프트웨어 - A3:보안 키 - A4:운전 이력 및 기록 데이터
3단계: 위협 분석 및 위험 평가(Threat analysis and risk assessment, TARA) 식별된 자산을 기반으로 다음 단계인 TARA를 수행한다. TARA는 자산이 위협에 의해 사이버 공격을 받았을 경우에 대해 피해 시나리오의 영향 등급과 공격 가능성 등급을 체계적으로 평가하여 위험 수준을 1(매우 낮음)에서 5(매우 높음)까지의 척도로 결정한다. 나아가 결정된 위험 수준에 따라 위험 처리 조치를 계획하고 실행할 수 있다. ISO 21434는 CAL1(낮음)에서 CAL4(높음)까지 모든 위협에 대해 사이버 보안 보증 수준(Cybersecurity assurance level, CAL) 적용을 선택적으로 제안한다. 다음은 피해 시나리오(Damage Scenario, DS)에 대한 몇 가지 예이다.
- A1-DS1:추돌 상황에서 운전자가 브레이크 페달을 밟아도 차량이 멈추지 않음 - A2-DS2:자율 주행에서 수동 전환 시 차선 변경이 안되어 차선 변경 실패로 인한 사고 발생
이를 기반으로 위협(Threat, T)을 식별하며 다음과 같다.
- A1-DS1-T1:제동 메시지 송수신 서비스 거부(DOS) 로 인해 제동 제어기가 제동을 수행하지 않음. - A2-DS2-T2:ADAS 조향 SW가 변경되어 오염된 SW로 인해 ADAS 수동 전환 기능이 동작하지 않음.
표 1은 공격 가능성 등급과 영향 등급을 보여준다. 위에서 식별된 자산과 피해 시나리오를 기반으로 위협을 평가하여 위험 수준과 CAL을 산출하였다.
표 1 | TARA 분석의 예
4단계: 사이버 보안 목표 및 사이버 보안 요구 사항 위험을 완화하기 위해 사이버 보안 목표를 식별하고 효과에 따라 평가한다. 사이버 보안 목표는 최상위 수준의 사이버 보안 요구 사항이다. 각 사이버 보안 목표로부터 하나 이상의 사이버 보안 요구사항들이 도출되고, 모든 사이버 보안 요구사항에 대해 하나 이상의 기술적 사이버 보안 요구사항이 도출된다. 이 예에서는 다음과 같다.
- 사이버 보안 목표(Cybersecurity Goal, SG) A1-T1-SG1 시스템은 운전자 지원 시스템에서 보낸 메시지가 조작되는 것을 방지해야 한다. - 사이버 보안 요구 사항(Cybersecurity Req., SeR) SG1-SeR1 운전자 지원과 센서 간의 통신 무결성이 보장되어야 한다. - 기술 사이버 보안 요구 사항(Technical Cybersecurity Req., TSeR) SG1-SeR1-TSeR1 메시지 인증 코드 (MAC)은 RSA2048 알고리즘을 사용하여 SHE(Secure Hardware Extension)와 호환되는 HTA(Hardware Trust Anchor)로 계 산되어야 한다. - 기술 사이버 보안 요구 사항(Technical Cybersecurity Req., TSeR) SG1-SeR1-TSeR2 MAC은 x바이트로 줄인 형태로 사용한다.
5단계: 추적성 추적성은 일관성을 유지하고 위험부담을 완화하는 데 도움이 된다. 변경 사항이 발생하고 지속적인 빌드 활동 중에도 적용범위와 일관성을 보장하는 데 필수적이다. 그림 4는 요구사항을 설계와 테스트에 연결시키는 추상화 모델을 보여준다. 한 예로, 부정적인 요구 사항, 즉 해커가 공격하기 위해 필요한 내용을 분석하고, 이로부터 해당 공격의 실현 가능성을 낮추기 위한 솔루션을 도출한다. 이것은 초기 TARA 및 보안 요구 사항 정의에서 완전한 추적성을 보장한다.
그림 4 | 삼중 피크 추상화모델에서 사이버 보안의 추적성
6단계: 설계 ADAS 시스템은 자산에 대해 TARA에서 발견된 위험 때문에 설계 변경을 필요로 한다. 사이버 보안 목표 SG1은 시스템이 네트워크 신호의 조작을 막기 위해 탐지 및 방지 메커니즘을 갖추고 있어야 한다는 점을 강조한다. 사이버 보안 개념을 기반으로 하여 탐지 및 방지 메커니즘을 설계할 수 있다.
이로 인해 하드웨어 설계도 변경해야 할 수 있다. 이 사례연구의 경우 HTA를 사용해야 한다. 소프트웨어의 경우MISRA 및 CERT 지침을 통한 보안 코딩은 보안 악용으로 이어질 수 있는 설계와 코드상의 오류를 방지하기 위해 적용한다. 대부분의 공격은 부적절한 설계로 인해 발생한다는 점을 항상 염두에 두어야 한다.
7단계: 통합 및 검증 이 단계에서의 주된 목표는 통합 구현된 보안 메커니즘이 사이버 보안 목표 및 요구 사항을 충족하는지 확인하는 것이다. 다음은 일반적으로 사이버 보안 검증 및 확인을 위해 권장되는 방법들이다.
- 단위 수준 검증:정적 및 동적 코드 품질 분석은 단위 수준에서의 강건성과 함께 MISRA 및 CERT와 같은 보안 코딩 지침에 중점을 둔다. 자동화 도구는 코드 품질 분석(Code Quality Analysis, CQA)을 수행하고 테스트 보고서를 생성하는 데 사용한다.
- 기능 테스트:요구 사항을 기반으로 하는 테스트는 시스템 설계 및 아키텍처의 기본적 결함을 식별하는 데 도움이 될 수 있다. 이 예에서 아이템의 정의 부분에서 설명한 실제 기능은 추가적인 보안 조치로 인해 기능의 성능이 손상되지 않았음을 시스템 차원에서 테스트한다. - 퍼지 테스트:퍼지 테스트는 예상 범위와 영역을 넘어서는 다양한 차량 통신 프로토콜을 테스트하는 데 사용된다. - 침투 테스트:침투 테스트는 구성 요소 및 시스템 차원에서 독립적으로 수행되는 테스트 전략이다. Gray Box Penetration Test[5]라는 테스트방식이 높은 효율성과 효과를 보여 이에 적합함이 입증되었다.
8단계: 개발 후 단계 유지보수 및 업데이트 관리는 제품 개발 과정 중에 준비되어야 한다. 여기에는 제품의 생산, 일반적인 운영 및 유지 관리, 그리고 마지막으로 폐기까지 포함된다. 사고 대응, 보안 경고 알림, 소프트웨어 패치와 배포 같은 활동을 위해 예산, 시간, 인력을 확보해야 한다. 이를 몇 가지 단계로 나누어 볼 수 있다.
- 생산:제품을 제조하고 조립하는 동안 여러 사이버 보안 요구 사항을 준수해야 한다. 예를 들어, 최종 생산라인에서 HTA의 메모리에 공급업체 또는 OEM 관련 암호 키 재료를 투입하는 것을 계획하고 처리해야 한다. - 운영 및 유지보수:모든 조직은 지속적인 사이버 보안 활동의 일환으로 프로젝트와는 독립된 모니터링 조직을 운영할 필요가 있다. 조직은 사이버 보안 이벤트가 발생했을 때 미리 정의하고 합의한 사이버 보안 사고 대응 계획에 따라 보안 사고를 처리해야 한다. - 폐기:제품 폐기시에 사이버 보안과 관련된 정보가 여전이 포함되어 있을 수 있으므로 이를 위한 폐기 단계에서의 절차 등에 대해 고려가 필요하다.
결론
차량 내에 IT 제품의 개발과, 생산 및 운영 분야의 기업 IT가 융합되면서 자동차 사이버 보안은 큰 연계성을 얻게 되었다[1, 2, 3, 4]. 이는 자동차 기능 안전을 위한 전제 조건이며 이해하기 쉽고 체계적으로 구현되어야 한다. ISO 21434는 자동차 사이버 보안을 위한 기본적인 지침으로, 이를 위한 프레임워크를 제공한다. 그러나 이를 실제 개발 프로세스로 정의할 때 있는 그대로 가져다 쉽게 적용할 수 있는 것은 아니다. ISO 21434를 효과적이고 효율적으로 구현하기 위해서는 전문적인 경험과 가이드가 필요하다. 이는 특히 차량 법규(UNECE R.155 CSMS)와 관련하여 나중에 그 효과가 입증되어야 하는 경우에 더욱 그렇다.
사이버 보안은 단지 보안 관련 조직 뿐만 아니라 제품의 수명 주기와 관련된 모든 관련자들의 책임이다. 깊이 있는 시스템 엔지니어링부터 시작하여 전체 제품 수명 주기 동안 관리되고 추적할 수 있는 총체적인 접근 방식이 필요하다.
[※] 이번 chapter에서는 지금까지 여러 차례 언급했던 각 device 및 HW를 어떻게 제어할 수 있는지에 대해 배워봅시다.
1. Device control
[※] 작은 것부터 큰 것까지 순서대로 register → memory → memory controller —> LCD(peripheral device)를 제어하는 방법에 대해 알아봅시다.
Device는 MCU 외부에 달려있는 IP를 의미하며, 대략 아래와 같은 구성과 흐름으로 이뤄진다.
CS핀 (Chip select) : 이 device를 사용하겠다고 활성화시키는 역할을 하는 핀으로 CE(Chip Enable)핀이라고 표기되기도 한다.CS/로 표기되는데, 슬래시는 ‘low active’라는 뜻이다. 따라서 이 device를 사용할 때는0을 입력해야 한다.
Data핀 : 양방향 핀으로 명령어 또는 데이터를 주고받는 용도로 사용하는 핀이다. 여러 개의 핀으로 구성될수도 있고, I2C/ SPI 등으로 한두가닥의 bus로 구현될 수도 있다.
CS를 low로 만들어서 ‘널 쓸거야’ 라고 알려준다.
Data핀으로 slave에게 command sequence를 보내서 명령한다.
Data핀으로 device는 제대로 수신했고 ready 상태임을 master에게 알려준다.
A의 12번째 bit인 A[11]에 접근하기 위해 1-byte 뒤인0x12345678 + 0x1에 접근해서는 안 된다.
왜냐하면,‘memory mapped I/O’라는 개념에 의해 레지스터든, 메모리든, 외부 peripheral이든 모두메모리에 접근하듯 align된 주소를 통해 접근 및 제어가 가능하기 때문이다.Memory mapped I/O란, 레지스터와 외부 I/O controller 등을 특정하는 주소를 메모리의 일부 영역에 할당해서 별다른 조치를 취하지 않고도 메모리를 제어하듯 레지스터와 외부 장치를 제어하는 기능을 말한다. 따라서 레지스터, 메모리, I/O peripheral 모두 특정 address에 접근하는 것으로 제어할 수 있다.
1.2. Memory & Memory controller
ARM core와 memory 사이에는 양방향 데이터 흐름을 제어하는 controller가 있다.
메모리도 위에서 배운 device 동작과정과 거의 동일한 과정을 거쳐서 제어할 수 있다.
CS를 low로 만들어 enable 한다.
OE(Output Enable)을 low(read) 또는 high(write)로 만든다.
Address line에 읽거나 쓰기를 원하는 주소를 지정한다.
([※] 보통 여기에 ALE (Address Latch Enable) 이라는 핀이 있어서, OE와 address가 준비되면 권총 트리거를 당겨서 쏘듯 slave에게 정보를 보내는 역할을 하는 핀이 추가로 있습니다.)
Data line에 read할 데이터가 뜨거나, write할 데이터를 보낸다.
CS를 high로 만들어 종료한다.
위 그림의 메모리는 address line이 26개이므로 2^24 == 64MB이고 data line은 8개이므로 주소당 1-byte를 저장할 수 있는 메모리다.
하지만, ARM core는 address line은 32개, data line도 32개를 가지고 있기 때문에 이런 메모리를 사용하기 위해서는 address line을 24개로, data line은 8개로 바꿔주는 회로가 필요하다.
바로 이 역할을 memory controller가 해준다.
Memory controller는 ARM core의 address line의 LSB 24-bit만 사용하고, data line의 LSB 8-bit만 사용해서 메모리에 접근할 수 있도록 도와준다.
만일 메모리를 하나 더 추가하거나 기존 메모리를 변경해서 128MB 구성이 된다면, controller 속의 bus sizer 레지스터를 제어해서 address line의 bit를 1개만 더 사용하도록 만들면 된다.
1.3. LCD
지금까지 배운 내용을 토대로 LCD 인터페이스를 제어하는 방법에 응용해보자.
어떤 MCP의 datasheet 속 memory map을 확인해보니 address0x2000_0000부터 3MB 크기가LCD_CS_N이라는 이름으로 선언돼있었다.
_N이라는 접미사가 붙은 것으로 보아 이 device의 CS핀은 low active임을 예측할 수 있다.
3MB이므로0x2000_0000 ~ 0x202F_FFFF영역이 LCD를 위한 영역임을 알 수 있다.
이제 datasheet를 넘겨서 LCD controller에 대한 회로를 설명하는 부분으로 넘어가보자.
이 controller는 특이하게도 address line의 7번 bit를 통해 command/ data 여부를 결정한다.
CS와 WD 그리고 RD는 모두 low active이고, 16개의 data line을 주고받는다.
위 정보들을 습득했으면 이제 SW개발자는 LCD를 제어할 수 있는 최소한의 정보를 얻은 것이다.
CAN-TP is a transport protocol that enables large data packets to be transmitted over the CAN bus, which has a limited message size. The protocol allows for the segmentation and reassembly of data packets, so that they can be transmitted in multiple smaller frames over the CAN bus.
Types of Addressing in CAN-TP (ISO 15765) Protocol
The main purpose of addressing in CAN-TP is for how to identify, either it is a non CAN-TP message or CAN-TP message. To identify it, there ae 2 types of addressing defined in the ISO 15765-2 standard.
Basic Addressing.
Extended Addressing.
Basic Addressing in CAN-TP (ISO 15765)
The CAN-TP Protocol basic addressing mode is called a normal addressing mode were to identify the CAN message or CAN-TP, we are using the CAN Identifier. So for this, there will be some identifier will be for CAN-TP, where if any message will receive then the server will understand that this TP message. The advantages of this type of addressing are that full 8 bytes of the data packet can be sent as data.
In basic addressing, each message is addressed to a specific node on the network using a unique identifier called a “Node Address.” Each node on the network is assigned a unique Node Address, which is typically configured by the user or by a configuration tool.
When a node wants to send a message, it includes the destination Node Address in the message header. When the message is received by the other nodes on the network, they compare the destination Node Address in the message header to their own Node Address. If the Node Address matches, the node accepts the message and processes it. If the Node Address does not match, the node ignores the message.
Extended Addressing in CAN-TP (ISO 15765)
Extended Addressing is a feature of the ISO 15765-2 Transport Protocol (CAN-TP) that allows messages to be addressed to a larger number of nodes on a Controller Area Network (CAN) than is possible with Basic Addressing. In Extended Addressing, the identifier field of the CAN message header is used to transmit the destination Node Address, which can be up to 29 bits in length. This allows for a much larger address space, with up to 536,870,912 possible Node Addresses, compared to the 8-bit Node Addresses used in Basic Addressing.
Extended Addressing also allows for dynamic addressing, where nodes can be added or removed from the network without requiring reconfiguration of the Node Addresses. This is accomplished through the use of a “Dynamic Addressing” scheme, where a unique “Arbitration ID” is assigned to each node, and the Node Address is transmitted in the data portion of the message.
When a node sends a message using Extended Addressing, it includes the destination Node Address in the identifier field of the CAN message header. When the message is received by the other nodes on the network, they compare the destination Node Address in the message header to their own Node Address. If the Node Address matches, the node accepts the message and processes it. If the Node Address does not match, the node ignores the message.
This addressing mode is the CAN-TP addressing mode where the 1st byte of the CAN data field will be used for the additional elements of the address whereby it reducing the data payload by one byte. The primary task of the transport protocol is to transfer messages which cannot be transmitted as a single Protocol Data Unit (PDU) due to their length. Messages which contain more data that can be transmitted within a single PDU are segmented by means of the transport protocol and divided into multiple, separate PDUs.
This procedure can also be implemented on the data link layer. The segmentation of the message must then be carried out in PDUs of the corresponding data link protocol. So to send the data like CAN, the CAN-TP Protocol has been designed. Let us discuss how it can send multiple frames.
Different Types of Frames in CAN-TP (ISO 15765)
So to make it possible, the CAN-TP also having 2 types of frames.Single FrameandMulti-Frame. Again the Multi-frame is having 3 types of frames. So total 4-types frames are there in CAN-TP:
In the ISO 15765-2 Transport Protocol (CAN-TP), a Single Frame is a type of message that is used to transmit data that can fit within a single CAN data frame. A Single Frame consists of a header and a data field, where the header contains information about the message, and the data field contains the actual data to be transmitted.
Single Frames are used to transmit small amounts of data, typically up to 7 bytes, that can be sent in a single CAN data frame. Single Frames are the simplest and most efficient way to transmit data in CAN-TP, as they require only one message to be sent and do not require any additional message framing or flow control mechanisms.
CAN-TP: Single Frame Format
If the data payload is 7-bytes or less than that, then the single frame will be used for the data transfer in CAN-TP Protocol. Where the first byte of the data field is used for addressing. Again this byte is divided into two divisions, where the MSB 4-bit is used for addressing of TP frame type called PCI (Protocol Control Information). The LSB 4-bit is used for the DLC (Data Length Code).
Example of Single Frame in CAN-TP (ISO 15765)
The below table shows an example of how the CAN-TP implemented in CAN Data field using Single Frame.
05
01
02
03
04
05
AA
AA
CAN Datafield with CAN-TP Using Single Frame(Request: Client –> Server)
PCI Header (0x05):1 Byte Protocol Control Information Header. Where,
Last 4 MSB is “0” and it defines the Frame Type is Single Frame.
First 4 bit LSB is “5” and it defines the payload or datalength transmitted in Single Frame.
Payload:Next 5 bytes are the original data (01 – 05) sent by the TransmitterECUand 2 byte is empty (NULL).
Generally, if you are going to send less than 8 byte, you can use the Single Frame else to send the more than that you have to use the other 3 frames. 0xAAorox55is filled for NULL data bytes to make sure that no junk or corrupted data sent by the transmitter.
First Frame (FF – 0x1) in CAN-TP (ISO 15765)
In Controller Area Network – Transport Protocol (CAN-TP) ISO15765-2, the “First Frame” refers to the first message frame in a multi-frame message. This message type is used to initiate the transmission of a large data block. It includes information such as the total size of the data block and the size of each subsequent frame.
When a large message is sent over the CAN bus, it is divided into several smaller frames to ensure reliable and efficient transmission. The First Frame is used to initiate this process and contains important information about the message, such as its total length and the number of frames that will be used to transmit it.
The structure of the First Frame message is defined by the ISO15765-2 standard and includes a header that contains information about the message, such as the message length and a unique identifier (ID) that allows the recipient to associate the message with the correct application. The data field of the First Frame contains the first part of the message data, up to a maximum of4096bytes.
Once the First Frame has been successfully transmitted and received, the following frames, known as Consecutive Frames, are sent to transmit the remaining parts of the message data. The use of multiple frames allows for more efficient use of the available bandwidth on the CAN bus and ensures reliable transmission even in noisy environments.
The first frame is an initial message of the multi-frame message packet in CAN-TP Protocol. It is used when more than 6 or 7 bytes of data segmented must be communicated. The first frame contains the length of the full packet, along with the initial data.
CAN-TP: First Frame Format
In FF, the first 2-bytes are used for the PCI, where the MSB 4-bit of the 1st byte is used for the type of frame and the LSB 4-bit and next 1-byte (total 8+4 = 12 bit)of the CAN data field is used for DLC (2^12 = 4096 data bytes). so in FF, only 6-bytes of the data can be transferred for the first time. This frame is responsible for sending the information to the receiver about the information as to how many total data bytes he is going to send.
Example of First Frame in CAN-TP (ISO 15765)
The below table shows an example of how the CAN-TP implemented in CAN Data field using First Frame.
10
64
01
02
03
04
05
06
CAN Datafield with CAN-TP Using First Frame (Request: Client –> Server)
PCI Header (0x1064):In FF, it is 2 byte.
Last 4 MSB is “1” is defining the Frame Type is First Frame.
First4LSB plus next 1 byte (Total = 4 LSB + 1 Byte) is Payload.0x0 + 0x64 = 0x64in decimal, it is100byte of data.
Payload:Next6bytes (01 – 06) are the original data that is sending to the receiver from total100bytes. So remaining 94 bytes will be sent consicutively by using the Consecutive Frames.
Consecutive Frame (CF)in CAN-TP (ISO 15765)
The Consecutive Frame or message type is used to transmit the data in consecutive segments. Each CF message contains a segment of data, as well as a sequence number that identifies the position of the segment within the larger data block.
The Consecutive Frame (CF) messages are used to transmit the actual data in a large data block. The size of each CF message is typically determined by the underlying CAN bus and network topology. The sequence number included in each CF message is used to ensure that the segments of data are received and reassembled in the correct order.
The primary task of the transport protocol or you can also CAN-TP Protocol is to transfer messages which cannot be transmitted as a single Protocol Data Unit (PDU) due to their length. Messages which contain more data that can be transmitted within a single PDU are segmented by means of the transport protocol and divided into multiple, separate PDUs. This procedure can also be implemented on the data link layer. The segmentation of the message must then be carried out in PDUs of the corresponding data link protocol.
CAN-TP: Consecutive Frame Format
In CF, the 1st byte is used for PCI byte, whereas the MSB 4-bit is defined for the type of frame and the LSB 4-bit is defined for the Sequence number. The sequence number always starts at 1 and increments with each frame sent (like as 1, 2,…, 15, 0, 1,…), with which lost or discarded frames can be detected. Each consecutive frame starts at 0, initially for the first set of the data in the first frame will be considered as 0th data. So the first set of CF(Consecutive frames) starts from “1”. There afterwards when it reaches “15”, it will be started from “0” by resetting the buffer register.
Example ofConsecutive Framein CAN-TP (ISO 15765)
The below table shows an example of how the CAN-TP implemented in CAN Data field using Consecutive Frame.
20
01
02
03
04
05
06
07
CAN Datafield with CAN-TP Using Consecutive Frame(Request: Client –> Server)
PCI Header (0x20):Here 20 is the 1 Byte PCI in CF.
Last 4 MSB is the Frame Type is “2” that defines the Consecutive Frame.
First 4 LSB is the Index of number or counter of blocks data is sends by the Transmitter ECU or node.Here it is “0” for the first consecutive frame.
Payload:Next remaining 7 bytes (01 – 07) are the original data to be sent to the receiver ECU or node.
Flow Control (FC) Frame in CAN-TP (ISO 15765)
The FC frame is the third and final message type in a three-frame sequence used for transmitting large data blocks that exceed the maximum size that can be transmitted in a single CAN message. This message type is used to manage the flow of data between the transmitter and the receiver. It includes information such as the number of consecutive frames that can be transmitted before the receiver must send an acknowledgement message.
The FC frame is sent by the receiver after it receives a CF message from the transmitter. The FC frame includes information such as the sequence number of the last received CF message, the status of the flow control mechanism, and the number of consecutive frames that can be transmitted by the transmitter before the receiver must send an acknowledgement message.
The information in the FC frame is used to manage the flow of data between the transmitter and the receiver to ensure that data is transmitted efficiently and reliably. By using flow control, the receiver can indicate to the transmitter how much data it can receive at any given time, preventing the transmitter from overloading the receiver with data and causing buffer overflow or other issues.
In conclusion, the flow control mechanism of the CAN-TP Protocol is used to configure the sender to match the properties of the receiver (timing, available receive buffer, readiness to receive). The FCF is always sent by the receiver so that to inform about the receiver capability of how the transmitter is going to send the data.
CAN-TP: Flow Control Frame Format
The flow control frame contains 3 bytes which together form a PCI in CAN-TP Protocol.
The first byte begins in the upper four bits with a value of 3, indicates that there is flow control. In the four least significant bits of the first byte shows a Flow Status (FS). Thus the transmitter to the receiver can signal whether a segmented transmission Clear To Send (CTS), Wait or Overflow.
FS = 0: Clear to Send.
FS = 1: Wait.
FS = 2: Overload.
The second byteBSstands for Block Size and shows how many consecutive frames need to be sent. So the Block Size is nothing but the number of Consecutive Frame.
The last byteSTminshows the minimum separation time between consecutive frames to be noticed.
Example ofFlow Control (FC) Framein CAN-TP (ISO 15765)
30
0A
14
AA
AA
AA
AA
AA
CAN Datafield with CAN-TP Using Consecutive Frame(Request: Server –>Client)
PCI Header:The total Flow Control Frame is PCI data and it is 3 byte.
0x30:First 4 MSB is “3” and it defines the Type of Frame that is Flow Control and Last 4 LSB is “0” that defines the Flow Status that is clear to send.
0x0A:This second byte is a1byte Block Size (BS) nothing but the number of Consecutive Frames. So here the receiver is informing to transmitter ECU to send the next0x0Aor10(in decimal) blocks or consecutive frames.
0x14:This third byte is a 1 byteSTminTime period in milli Second. Here it is0x14nothing but the20(in decimal). That means the Transmitter ECU will send each CF in the delay of20milli second to the receiver ECU or node.
An ISO-TP frame is always 8 bytes long and unneeded bytes filled with the padding byte as 0xAA or 0x55.
Working Principle of CAN-TP (ISO 15765)
There are two types of data transfer methods of CAN-TP Protocol: single-frame data transmission and multiple data transmission. The single-frame data transmission (Unacknowledged Unsegmented Data Transfer) and the Multi-frame Datatransmission(Unacknowledged Segmented Data Transfer). In a CAN frame, there is a maximum of 8 data bytes of user data. The data length of the ISO TP message can reach a maximum of 4095 bytes. If an ISO TP message length exceeds the data length of 8 data bytes,the UDSmessage must be segmented.
The CAN-TP protocol works by dividing large data into smaller packets called Transport Protocol Data Units (TPDUs). These TPDUs are then transmitted over the CAN bus, with each TPDU containing a sequence number and checksum to ensure data integrity. The receiver then reassembles the TPDUs into the original data message.
Single Frame Communication
CAN-TP ISO15765 Single Frame Communication
Multi-Frame Communication
CAN-TP for Multi-Frame Communication
Below is an example of how the CAN-TP protocol could work in a client-server communication scenario:
The client sends a large data message to the server, which exceeds the maximum size of a single CAN message.
The client software breaks the large message into smaller TPDUs, each with its own sequence number and checksum.
The client software sends the TPDUs to the server over the CAN bus by using the First Frame (FF).
The server software receives the TPDUs and verifies the sequence numbers and checksums to ensure that all packets have been received and that the data is intact.
Once all TPDUs have been received and verified, the server software reassembles the TPDUs into the original data message.
The server software then sends an Flow Control message back to the client, indicating that how, when, & How much the data should be send by the Transmitter ECU.
The client software receives the acknowledgement message (FC message) and can continue with its operations by using the Consecutive Frames until the next command from Receiver ECU or as per the Flow Control data or information provided by the Transmitter ECU.
Error Handlingin CAN-TP (ISO 15765)
In CAN-TP Protocol, Both the transmitter and receiver monitors the data transmission with a timer. The receiver monitors the time required by the transmitter for sending Consecutive Frames. If this takes a long time, the transmission is aborted and data already transmitted are discarded. Similarly, the transmitter monitors the time for the receiver to send the flow control frame. Again the transmission is aborted and data already transmitted are discarded if a timeout is detected. The maximum waiting time for a frame is one second.
Generally, In addition to timing errors, errors in the message structure must be recognized. If an erroneous PDU is detected the frame is ignored or if a transmission is in progress, canceled it. Possible errors in the message structure are incorrect sequence numbers in consecutive frames, invalid message length, and invalid flow status in the flow control frames or an invalid PDU type. Unexpectedly arriving frames are always ignored, with the exception of a single frame and physically addressed the first frame. Functionally addressed first frame, consecutive frame, and flow control are always ignored.
How to send 100 bytes of data using CAN-TP Protocol?
I hope after learning this tutorial, you will be able to write this answer in below comments. Thank you everyone for giving your time to learn step by step about the CAN-TP Tutorial.
The HamsterWheel: An In-Depth Exploration of a Novel Attack Vector on the Sui Blockchain
2023. 6. 19.
CertiK’s Skyfall team identified and disclosed a series of denial of service vulnerabilities in the Sui blockchain. Among these vulnerabilities, a new type of bug stood out due to its critical severity implications which could cause the Sui network to not be able to process new transactions, effectively causing a total network shutdown. This unique attack, different from previous known ones, allows an attacker to induce an infinite loop in the validator node by merely submitting a small payload of approximately 100 bytes. Moreover, this attack creates persistent damage that endures even after the validator network reboots. We've dubbed this unique type of attack "HamsterWheel.”
Upon discovery, we responsibly reported this vulnerability to Sui through their bug bounty program. Sui's response was prompt and efficient. They confirmed the critical severity of the vulnerability and took steps to address the issue before the network’s mainnet launch. In addition to fixing this particular vulnerability, Sui also implemented preventative mitigations to lessen the potential damage caused by exploitation.
In appreciation for the responsible disclosure, Sui network awarded a $500,000 bounty award to CertiK Skyfall team.
In this blog post, we will disclose the technical aspects of this critical vulnerability, shedding light on its root cause and potential impact.
The Vulnerability In Detail
The Critical Role of Verifiers in Sui
In Move-based blockchains, such as Sui and Aptos, the safeguarding mechanism against malicious payloads rests heavily on static verification techniques. These techniques inspect user-submitted payloads before a contract is either published or upgraded on the chain. With checkers ensuring both structural and semantic correctness, the Move runtime presumes their soundness.
Figure 1:The threats of malicious payloads on Move-based chains
Sui implements a memory model that is distinct from the original Move design, deploying a customized version of Move VM for contract development. Sui goes the extra mile in strengthening its safety measures against malformed payloads. It introduces additional, customized verifiers, dubbed as Sui verifiers. These specialized verifiers cater to Sui's unique features, such as object safety and global storage access safety, among others.
Figure 2:Sui's sequence of checks against the payload
Most verifiers conduct structural assessments against the CompiledModule, the runtime representation of user-provided contract payloads. For instance, duplication-checker ensures no duplicate entries in each section, while limits-checker affirms the upper bounds of entries allowed in each section. However, more complex analyses are necessary for static checking to guarantee the semantic soundness of the untrusted payloads.
Understanding Move's Abstract Interpreter: Linear and Iterative Analysis
The Abstract Interpreter, furnished by Move, is a framework specially designed for executing complex security analysis on bytecode via abstract interpretation. This mechanism enables a more refined and accurate verification process, with each verifier being allowed to define their unique abstract state for the analysis.
Beginning its operation, the Abstract Interpreter constructs Control Flow Graphs (CFGs) from compiled modules. Each Basic Block within these CFGs maintains a set of states, namely, pre-state and post-state. The pre-state offers a snapshot of the program prior to the execution of a Basic Block, while the post-state provides an image of the program after the Basic Block's execution.
When the Abstract Interpreter encounters no backedge (or loop) in the Control Flow Graph, it follows a simple linear execution. Each BasicBlock is analyzed in sequence, with the pre-state and post-state calculated based on the semantics of each instruction within the block. The result is an accurate snapshot of the program's state at each point in the execution, which aids in verification of the program's safety properties.
Figure 3:Move Abstract Interpreter’s workflow
However, when loops are present in the control flow, the process becomes more complex. Backedges, which signal the presence of loops, require the Abstract Interpreter to carefully manage the merging of states. This is due to the interdependence between the state at the start of the loop (the pre-state of the loop header) and the state at the end of the loop (the post-state of the loop footer).
In handling backedges, the Abstract Interpreter meticulously merges the pre-state of the target Basic Block with the post-state of the current Basic Block. If discrepancies are detected in the resulting merged state, the Abstract Interpreter initiates a re-analysis, beginning from the target Basic Block with the updated merged state.
This iterative analysis process continues until the loop's pre-state stabilizes. In other words, the process is repeated until the pre-state of the loop header no longer changes between iterations, indicating that a fixed point has been reached and the analysis of the loop is complete.
Sui's blockchain platform introduces a unique object-centric global storage model, which differentiates it from the original Move design. A distinctive feature of this model is that any struct with a 'key' ability must initiate with an ID field with the ID type. The ID field is immutable and cannot be transferred to other objects, as each object must have a unique ID. To ensure this, Sui utilizes custom analysis built upon the Abstract Interpreter.
/// Sui object identifiers module sui::object { ... struct UID has store { id: ID, } struct ID has copy, drop, store { bytes: address } } /// Sui object example struct A has key { id: UID, b: B, }
The IDLeak Verifier, alternatively known as the id_leak_verifier, operates in concert with the Abstract Interpreter to conduct its analysis. It forms its distinct AbstractDomain, termed as AbstractState, to oversee the status of each local variable using an AbstractValue. This value denotes whether the ID is fresh. During the process of struct packing, the IDLeak Verifier checks that only a fresh ID is allowed to be packed into a structure. It meticulously traces the data flow of local states to ensure that no existing ID is transferred to other objects.
The State Management Inconsistency in Sui IDLeak Verifier
The IDLeak Verifier integrates with the Move Abstract Interpreter by implementing the AbstractState::join function. This function plays integral roles in state management, notably in merging and updating state values. Let's examine these functions in detail to understand their operation.
enum AbstractValue { Fresh, Other, } pub(crate) struct AbstractState { locals: BTreeMap<LocalIndex, AbstractValue>, } impl AbstractDomain for AbstractState { /// attempts to join state to self and returns the result fn join( &mut self, state: &AbstractState, _meter: &mut impl Meter, ) -> Result<JoinResult, PartialVMError> { let mut changed = false; for (local, value) in &state.locals { let old_value = *self.locals.get(local).unwrap_or(&AbstractValue::Other); changed |= *value != old_value; // determines the return value. self.locals.insert(*local, value.join(&old_value)); // update state value. } if changed { Ok(JoinResult::Changed) } else { Ok(JoinResult::Unchanged) } } }
In AbstractState::join, the function takes another AbstractState as input and attempts to merge its local state with the current object's local state. For each local variable in the incoming state, it compares the variable's value to its current value in the local state (with a default value of AbstractValue::Other if not found). If the two values are unequal, it sets a 'changed' flag and updates the local variable's value in the local state by calling AbstractValue::join.
In AbstractValue::join, the function compares its value with another AbstractValue. If they are equal, it returns the incoming value. If not, it returns AbstractValue::Other.
However, the conjunction of these functions can lead to a potential inconsistency. Although AbstractState::join may indicate a change (JoinResult::Changed) due to differing old and new values, the state value after the update might remain the same. This anomaly occurs due to the order of operations: the determination of changed status in AbstractState::join happens before AbstractValue::join, which doesn't reflect the genuinely updated state value. Besides, in AbstractValue::join, AbstractValue::Other dominates the joined result. Thus, if the old value is AbstractValue::Other and the new value is AbstractValue::Fresh, the updated state value remains unchanged as AbstractValue::Other.
Figure 4:A concrete example illustrating the inconsistency in State Join
This introduces an inconsistency where the Basic Block state is marked as changed, but the state value itself remains unchanged. Such inconsistency can potentially have significant implications. To understand why, it's crucial to recall the abstract interpreter's behavior in the presence of a loop within the Control Flow Graph (CFG). When encountering a loop, the abstract interpreter employs an iterative approach to merge the target (backedge) and current state. If the joined state changes as a result of this merge, the abstract interpreter triggers a reanalysis.
However, if the join operation falsely flags the state as changed, when in reality no change in value has occurred, it could lead to an endless cycle of reanalyses.
Beyond the Inconsistency: Triggering Infinite Analysis in Sui IDLeak Verifier
Leveraging this inconsistency, an attacker could craft a malicious control flow graph that tricks the IDLeak verifier into an infinite loop. The crafty control flow graph would consist of three basic blocks, BB1 and BB2, BB3. We intentionally introduce a backward edge from BB3 to BB2.
Figure 5:Malicious CFG + State construction that can cause deadloop inside IDLeak verifier
The process starts with BB2, where the AbstractValue for a particular local variable is set to ::Other. After executing BB2, the flow moves to BB3, where the same variable is set to ::Fresh. At the end of BB3, there's a backward edge that leads back to BB2.
Here's where inconsistency plays a crucial role. When the backward edge is processed, the AbstractInterpreter attempts to join the post-state of BB3 (where the variable is 'Fresh') with the pre-state of BB2 (where the variable is 'Other'). The AbstractState::join function notices the difference and sets the 'changed' flag, signaling that reanalysis of BB2 is necessary. However, the dominating behavior of 'Other' in AbstractValue::join means that the actual state of the variable remains 'Other'.
So, when the verifier continues to reanalyze BB2, along with all its successors (BB3 in this case). This looping process, once initiated, continues indefinitely. The verifier consumes all available CPU cycles, effectively causing a deadlock in transaction processing – a situation that persists even after a validator reboot. This cleverly crafted vulnerability, which we've termed the "HamsterWheel" attack, effectively brings the Sui validator to a halt.
With the conceptual attack scenario delineated and all pre-assumed verifier checkers validated, we successfully demonstrate the exploit by constructing a concrete example using the following Move bytecodes:
The demonstration highlights the vulnerability in practice. It showcases how, through the careful crafting and manipulation of bytecodes, an attacker can trigger an infinite loop in the IDLeak verifier, where a mere 100 byte payload can consume all available CPU cycles, effectively blocking the processing of new transactions and resulting in a denial of service on the Sui validator.
The HamsterWheel Attack Causes Persistent Damage to the Blockchain Network
According to the bug bounty conditions set by Sui, for a vulnerability to reach the level of critical severity, it must exhibit a capacity to bring the entire network to a halt, impeding new transaction confirmations and requiring a hard fork for resolution. Lesser impacts, such as partial denial of service, can at best qualify as medium or high severity based on the parameters of the bug bounty program.
The HamsterWheel attack discovered by the CertiK Skyfall team carries an immense threat due to its potential to shut down the entire Sui network, an impact that earns it the classification of critical severity. To understand the gravity of this flaw, it is necessary to comprehend the intricate architecture of Sui's backend system, specifically the steps leading up to the publishing or upgrading of a transaction on the chain.
Figure 6:Outline of interactions to commit a transaction in Sui
Initially, user transactions are directed towards the Sui authorities via a Frontend RPC and pre-validation process. The Sui authorities are responsible for validating the incoming transactions. Following successful validation of the user's signature, the transactions are converted into the formation of transaction certificates.
These certificates, integral to the functioning of the network, are then propagated across the validator nodes. Before the transaction can be published or upgraded on the chain, the validator nodes scrutinize these certificates for validity. It's during this crucial stage of verification that the discovered 'deadloop' vulnerability can be exploited.
When the flaw is triggered, it leads to an indefinite hang in the verification process. It effectively hampers the ability of the system to process new transactions, causing a total network shutdown. The criticality of this vulnerability is further magnified as it persists even after a validator reboot, meaning conventional mitigations are insufficient. The exploitation of this vulnerability hence leads to a 'persistent damage' scenario, leaving a lasting impact on the entire Sui network.
Sui’s Approach to Mitigation
In response to the vulnerability, Sui confirmed the vulnerability in a timely manner and released a fix to address the critical flaw. The fix ensures consistency between the state change and the changed flag, eliminating the critical impact caused by the critical HamsterWheel attack.
// sui-verifier/src/id_leak_verifier.rs impl AbstractDomain for AbstractState { /// attempts to join state to self and returns the result fn join( &mut self, state: &AbstractState, _meter: &mut impl Meter, meter: &mut impl Meter, ) -> Result<JoinResult, PartialVMError> { let mut changed = false; for (local, value) in &state.locals { let old_value = *self.locals.get(local).unwrap_or(&AbstractValue::Other); - changed |= *value != old_value; - self.locals.insert(*local, value.join(&old_value)); + let new_value = value.join(&old_value); + changed |= new_value != old_value; + self.locals.insert(*local, new_value); } ... } }
In order to eliminate the aforementioned inconsistency, Sui's fix consisted of a minor but crucial adjustment to AbstractState::join function. Instead of determining the changed result prior to the execution of AbstractValue::join, this fix ensures that the AbstractValue::join is carried out first. Subsequently, the changed flag is set by comparing the result of AbstractValue::join with the old_value. This way, the changed flag correctly represented whether a change was made in the final state value.
In addition to fixing this specific vulnerability, Sui also deploys mitigations to reduce the impact of future verifier vulnerabilities. According to Sui’s reply in the bug report, the mitigation is involved with a feature called Denylist.
“However, validators have a node config file that allows them to temporarilydenylistcertain classes of transactions. This config can be used to temporarily disable processing publishing and package upgrades. Since the bug happens while running the Sui verifier before signing a publish or package upgrade tx, and denylisting will stop the verifier from being run + drop the malicious tx on the floor temporarily denylisting these tx types is a 100% effective mitigation (though it will temporarily interrupt service for folks attempting to publish or upgrade code).
As a side note, we have had this tx denylist config file for awhile, but we alsoadded one for certificatesas a follow up item to the "validator deadloop" bug you previously reported. With this mechanism in place, we would be much more resilient to that attack: we would use the certificate denylist config to make validators forget about the bad cert (breaking the crash loop), and the tx denylist config to disable publishing/upgrades and thus prevent creation of new transactions of death. Thanks for making us think about this!”
Validators have a finite number of "ticks" (different from gas) to spend on bytecode verification before signing a transaction, if all bytecode being published in a transaction cannot be verified in that many ticks, the validator will refuse to sign the transaction, preventing it from being executed on the network. Previously, metering only applied to a chosen set of complicated verifier passes. In response to this issue, we extended metering to every verifier pass, to guarantee a bound on the work a validator performs during verification per tick. We also fixed the underlying infinite loop bug in the ID Leak verifier pass.
To summarize, the Denylist enables validators to temporarily circumvent the verifier routine by disabling the publishing or upgrading processes, effectively preventing some potential disruptions from problematic transactions. Given the Denylist mitigation in place, validators should remain operational with only a portion of their functionality disabled when facing verifier panics.
Timeline
April 27, 2023: CertiK reports the vulnerability to Sui.
April 28, 2023: Sui confirms the vulnerability, severity is pending for confirmation.
April 28, 2023: Sui patched the vulnerability in commit 7915de5.
April 30, 2023: Sui confirms the severity as CRITICAL.
May 16, 2023: Sui pays the bug bounty reward.
Conclusion
In this blog post, we delved into the technical aspects of the HamsterWheel attack identified by the CertiK Skyfall team. We explained how this innovative form of attack leverages a critical vulnerability to result in a complete network shutdown of the Sui blockchain. Additionally, we took a closer look at Sui's timely responses to fix this critical issue, sharing their approach to mitigate the Sui blockchain against future threats.
리눅스 기반 시스템의 기본 바이너리 형식인 ELF(Executable and Linkable Format)을 살펴보자.
ELF는 실행 가능한 바이너리 파일, 목적 파일, 공유 라이브러리, 코어 덤프 등에서 사용되는 형식이다. 여기서는 64비트의 실행 가능한 바이너리 파일을 중심으로 살펴보겠다.
A 64-bit ELF binary at a glance
ELF 바이너리는 ELF 파일 헤더, 프로그램 헤더, 그리고 섹션들과 섹션 헤더들로 이루어져 있다.
Executable Header
모든 ELF 파일은 executable header로 시작하며, /usr/include/elf.h에서 확인할 수 있다.
/usr/include/elf.h의Elf64_Ehdr정의
typedef struct {
unsigned char e_ident[EI_NIDENT]; /* Magic number and other info */
Elf64_Half e_type; /* Object file type */
Elf64_Half e_machine; /* Architecture */
Elf64_Word e_version; /* Object file version */
Elf64_Addr e_entry; /* Entry point virtual address */
Elf64_Off e_phoff; /* Program header table file offset */
Elf64_Off e_shoff; /* Section header table file offset */
Elf64_Word e_flags; /* Processor-specific flags */
Elf64_Half e_ehsize; /* ELF header size in bytes */
Elf64_Half e_phentsize; /* Program header table entry size */
Elf64_Half e_phnum; /* Program header table entry count */
Elf64_Half e_shentsize; /* Section header table entry size */
Elf64_Half e_shnum; /* Section header table entry count */
Elf64_Half e_shstrndx; /* Section header string table index */
} Elf64_Ehdr;
Elf64_Ehdr 구조체의 각 원소들의 자료형인 Elf64_Half, Elf64_Word 등은 uint16_t와 uint32_t다.
ELF 파일 헤더의 각 필드
Section Headers
ELF 바이너리의 코드와 데이터는 섹션(section)으로 나누어져 있다.
섹션의 구조는 각 섹션의 내용이 구성된 방식에 따라 다른데, 각 섹션 헤더(section header)에서 그 속성을 찾을 수 있다. 바이너리 내부의 모든 섹션에 대한 헤더 정보는 섹션 헤더 테이블(section header table)에서 찾을 수 있다.
섹션은 링커가 바이너리를 해석할 때 편리한 단위로 나눈 것이다.
링킹이 수반되지 않은 경우에는 섹션 헤더 테이블이 필요하지 않다. 만약 섹션 헤더 테이블 정보가 없다면 e_shoff 필드는 0이다.
바이너리를 실행할 때 바이너리 내부의 코드와 데이터를 세그먼트(segment)라는 논리적인 영역으로 구분한다.
세그먼트는 링크 시 사용되는 섹션과는 달리 실행 시점에 사용된다.
/usr/include/elf.h의Elf64_Shdr구조체 정의
typedef struct {
Elf64_Word sh_name; /* Section name (string tbl index) */
Elf64_Word sh_type; /* Section type */
Elf64_Xword sh_flags; /* Section flags */
Elf64_Addr sh_addr; /* Section virtual addr at execution */
Elf64_Off sh_offset; /* Section file offset */
Elf64_Xword sh_size; /* Section size in bytes */
Elf64_Word sh_link; /* Link to another section */
Elf64_Word sh_info; /* Additional section information */
Elf64_Xword sh_addralign; /* Section alignment */
Elf64_Xword sh_entsize; /* Entry size if section holds table */
} Elf64_Shdr;
섹션 헤더의 각 필드
Sections
GNU/Linux 시스템의 ELF 파일들은 대부분 표준적인 섹션 구성으로 이루어져 있다.
$ readelf --sections --wide a.out
There are 29 section headers, starting at offset 0x1168:
Section Headers:
[Nr] Name Type Address Off Size ES Flg Lk Inf Al
[ 0] NULL 0000000000000000 000000 000000 00 0 0 0
[ 1] .interp PROGBITS 0000000000400238 000238 00001c 00 A 0 0 1
[ 2] .note.ABI-tag NOTE 0000000000400254 000254 000020 00 A 0 0 4
[ 3] .note.gnu.build-id NOTE 0000000000400274 000274 000024 00 A 0 0 4
[ 4] .gnu.hash GNU_HASH 0000000000400298 000298 00001c 00 A 5 0 8
[ 5] .dynsym DYNSYM 00000000004002b8 0002b8 000060 18 A 6 1 8
[ 6] .dynstr STRTAB 0000000000400318 000318 00003d 00 A 0 0 1
[ 7] .gnu.version VERSYM 0000000000400356 000356 000008 02 A 5 0 2
[ 8] .gnu.version_r VERNEED 0000000000400360 000360 000020 00 A 6 1 8
[ 9] .rela.dyn RELA 0000000000400380 000380 000018 18 A 5 0 8
[10] .rela.plt RELA 0000000000400398 000398 000030 18 AI 5 24 8
[11] .init PROGBITS 00000000004003c8 0003c8 00001a 00 AX 0 0 4
[12] .plt PROGBITS 00000000004003f0 0003f0 000030 10 AX 0 0 16
[13] .plt.got PROGBITS 0000000000400420 000420 000008 00 AX 0 0 8
[14] .text PROGBITS 0000000000400430 000430 000192 00 AX 0 0 16
[15] .fini PROGBITS 00000000004005c4 0005c4 000009 00 AX 0 0 4
[16] .rodata PROGBITS 00000000004005d0 0005d0 000012 00 A 0 0 4
[17] .eh_frame_hdr PROGBITS 00000000004005e4 0005e4 000034 00 A 0 0 4
[18] .eh_frame PROGBITS 0000000000400618 000618 0000f4 00 A 0 0 8
[19] .init_array INIT_ARRAY0000000000600e10 000e10 000008 00 WA 0 0 8
[20] .fini_array FINI_ARRAY0000000000600e18 000e18 000008 00 WA 0 0 8
[21] .jcr PROGBITS 0000000000600e20 000e20 000008 00 WA 0 0 8
[22] .dynamic DYNAMIC 0000000000600e28 000e28 0001d0 10 WA 6 0 8
[23] .got PROGBITS 0000000000600ff8 000ff8 000008 08 WA 0 0 8
[24] .got.plt PROGBITS 0000000000601000 001000 000028 08 WA 0 0 8
[25] .data PROGBITS 0000000000601028 001028 000010 00 WA 0 0 8
[26] .bss NOBITS 0000000000601038 001038 000008 00 WA 0 0 1
[27] .comment PROGBITS 0000000000000000 001038 000034 01 MS 0 0 1
[28] .shstrtab STRTAB 0000000000000000 00106c 0000fc 00 0 0 1
Key to Flags:
W (write), A (alloc), X (execute), M (merge), S (strings), l (large)
I (info), L (link order), G (group), T (TLS), E (exclude), x (unknown)
O (extra OS processing required) o (OS specific), p (processor specific)
.init섹션에는 초기화에 필요한 실행 코드가 포함된다. 운영체제의 제어권이 바이너리의 메인 엔트리로 넘어가면 이 섹션의 코드부터 실행된다.
.fini섹션은 메인 프로그램이 완료된 후에 실행된다. .init과 반대로 소멸자 역할을 한다.
.init_array섹션은 일종의 생성자로 사용할 함수에 대한 포인터 배열이 포함된다. 각 함수는 메인 함수가 호출되기 전에 초기화되며 차례로 호출된다. .init_array는 데이터 섹션으로 사용자 정의 생성자에 대한 포인터를 포함해 원하는 만큼 함수 포인터를 포함할 수 있다.
.fini_array섹션은 소멸자에 대한 포인터 배열이 포함된다. .init_array와 유사하다. 이전 버전의 gcc로 생성한 바이너리는 .ctors와 .dtors라고 부른다.
.text섹션에는 메인 함수 코드가 존재한다. 사용자 정의 코드를 포함하기 때문에 SHT_PROGBITS라는 타입으로 설정되어 있다. 또한 실행 가능하지만 쓰기는 불가능해 섹션 플래그는 AX다._start,register_tm_clones,frame_dummy와 같은 여러 표준 함수가 포함된다.
.rodata섹션에는상숫값과 같은 읽기 전용 데이터가 저장된다.
.data섹션은초기화된 변수의 기본값이 저장된다. 이 값은 변경되어야 하므로 쓰기 가능한 영역이다.
.bss섹션은초기화되지 않은 변수들을 위해 예약된 공간이다. BSS는 심벌에 의해 시작되는 블록 영역(Block Strarted by Symbol)이라는 의미로, (심벌) 변수들이 저장될 메모리 블록으로 사용한다.
.rel.*와.rela.*형식의 섹션들은 재배치 과정에서 링커가 활용할 정보를 담고 있다. 모두 SHT_RELA 타입이며 재배치 항목들을 기재한 테이블이다. 테이블의 각 항목은 재배치가 적용돼야 하는 주소와 해당 주소에 연결해야 하는 정보를 저장한다.동적 링킹 단계에서 수행할 동적 재배치만 남아 있다. 다음은 동적 링킹의 가장 일반적인 두 타입이다.
GLOB_DAT(global data): 이 재배치는 재배치는 데이터 심벌의 주소를 계산하고 .got의 오프셋에 연결하는 데 사용된다. 오프셋이 .got 섹션의 시작 주소를 나타낸다.이 엔트리의 오프셋은 해당 함수에서 간접 점프하는 점프 슬롯의 주소(rip로부터의 상대 주소로 계산)다.
JUMP_SLO(jump slots): .got.plt 섹션에 오프셋이 있으며 라이브러리 함수의 주소가 연결될 수있는 슬롯을 나타냅니다. 엔트리는 점프 슬롯(jump slot)이라고 부른다.
.dynamic섹션은 바이너리가 로드될 때 운영체제와 동적 링커에게 일종의 road map을 제시하는 역할을 한다. 일명 태그(tag)라고 하는 Elf64_dyn 구조의 테이블을 포함한다. 태그는 번호로 구분한다.DT_NEEDED 태그는 바이너리와 의존성 관계를 가진 정보를 동적 링커에게 알려준다.게다가 동적 링커의 수행에 필요한 중요한 정보들을 가리키는 역할을 하기도 한다. 예를 들어 동적 문자열 테이블(DT_STRTAB), 동적 심벌 테이블(DT_SYMTAB), .got.plt 섹션(DT_PLTGOT), 동적 재배치 섹션(DT_RELA) 등.
DT_VERNEED와 DT_VERNEEDNUM 태그는 버전 의존성 테이블(version dependency table)의 시작 주소와 엔트리 수를 지정한다.
.shstrtab섹션은 섹션의 이름을 포함하는 문자열 배열이다. 각 이름들을 숫자로 인덱스가 매겨져 있다.
.symtab섹션에는 Elf64_Sym 구조체의 테이블인 심벌 테이블이 포함되어 있다. 각 심벌 테이블은 심벌명을 함수나 변수와 같이 코드나 데이터와 연관시킨다.
.strtab섹션에는 심벌 이름을 포함한 실제 문자열들이 위치한다. 이 문자열들 Elf64_Sym 테이블과 연결된다. 스트립 된 바이너리에는 .symtab과 .strtab 테이블은 전부 삭제된다.
.dynsym섹션과.dynstr섹션은 동적 링킹에 필요한 심벌과 문자열 정보를 담고 있다는 점을 제외하면 .symtab이나 .strtab와 유사하다.정적 심벌 테이블은 섹션 타입이 SHT_SYMTAB이고 동적 심벌 테이블은 SHT_DYNSYM 타입이다.
Program Headers
프로그램 헤더 테이블은 바이너리를 세그먼트의 관점에서 볼 수 있게 해준다.
바이너리를 섹션 관점에서 보는 것은 정적 링킹의 목적만으로 한정하는 것이다.
세그먼트의 관점으로 본다는 것은 운영체제와 동적 링킹 과정을 통해 바이너리가 프로세스의 형태가 되고, 그와 관련된 코드와 데이터들을 어떻게 처리할 것인지를 다룬다는 의미다.
PLT는 <puts@plt-0x10>:와 같이 구성되어 있다. 다음으로 일련의 함수들이 나타나며 모두 라이브러리 함수 각각에 대한 것이고 스택에 값이 1씩 증가되며 push 한다.
PLT를 사용해 동적으로 라이브러리 함수 참조
라이브러리 함수 중 하나인 puts 함수 호출할 때 PLT 구조를 사용해 puts@plt와 같이 호출할 수 있다➊.
PLT 구문은 간접 점프 명령으로 시작하며, .got.plt 섹션에 저장된 주소로 점프한다➋. 지연 바인딩 전에는 이 주소가 puts@plt의 다음 명령어 주소를 가리키고 있다.
스택에 push 하는 값은 PLT 구문에서 함수들을 식별하기 위한 번호다➌.
다음 명령을 통해 default stub으로 이동한다➍.
default stub은 GOT에서 가져온 또 다른 식별자를 스택에 push하고, 동적 링커 부분으로 점프(GOT로 다시 간접 점프)한다➎.
PLT 구문에 의해 스택에 push된 이 식별 정보를 통해 동적 링커는 puts 함수 주소를 찾을 수 있음을 확인하고, puts 함수를 대신 호출한다. 동적 링커는 puts 함수 주소를 찾고 puts@plt와 관련된 GOT 테이블의 항목에 해당 함수의 주소를 연결(기록)한다.
이후 puts@plt를 호출하면 GOT 테이블 내부에는 패치를 통해 실제 puts 함수의 주소가 저장되어 있으므로 PLT 구문으로 점프될 때 (앞서 다룬) 동적 링커 작업을 반복하지 않고 즉시 puts 함수로 점프한다➏.
GOT를 사용하는 이유
PLT 코드에 라이브러리 주소를 바로 쓰지 않고 GOT와 함께 사용하는 이유는 보안상의 문제 때문이다. 바이너리에 취약점이 존재하는 경우 공격자가 PLT overwrite를 이용해 exploit 할 수 있기 때문이다. 물론 GOT 내부의 주소를 변경해 공격하는 GOT overwrite 기법도 발표되긴 하였으나 난이도가 더 높다.
최근 몇 년 동안 보안 관련 기능이 차량에 탑재돼 왔다. 예를 들어 자동차 도난방지 장치와 ECU의 보안 프로그래밍에 암호화 및 서명 확인 등과 같은 암호화 방식이 활용되고 있다. 커넥티비티에 관한 지속적인 트렌드는 차량이 지원하는 기능의 범위를 확장하는 것이다. 예를 들어 무선(OTA) 소프트웨어 업데이트, 원격 기능 활성화 및 차량과 인프라 간 통신(V2X) 등이 있다. 이러한 유스케이스를 통해 자동차 업계에는 흥미롭고, 매우 유망한 비즈니스 모델이 탄생한다. 하지만 연결 수가 증가할수록 차량에 대한 잠재적인 사이버 공격수 또한 증가한다.
키: 사이버 보안의 기초 사이버 공격 위험에 대응하기 위해 자동차 업계는 자동차 업계 고유의 보안조치를 구현하며 기존의 IT 보안 분야의 프로토콜을 배포하고 있다. 예를 들어 AUTOSAR의 표준화된 SecOC(보안 온보드 통신)[1]은 ECU와 차량 네트워크 내 ECU 간 통신을 보호한다. 버스 기술과 특정 애플리케이션, 예를 들어 IT 분야에서 자주 언급되는 TLS(전송 계층 보안)와 IPSec(인터넷 프로토콜 보안) 프로토콜이 사용될 수 있다. 모든 최신 보안 메커니즘에서 공유돼야 할 한 가지 특징은 사용된 암호화 알고리즘 세부사항의 기밀성이 아니라 사용된 키의 기밀성에 기초한다. 보안을 더 많이 개선하기 위해 주어진 키는 한 개의 보안 메커니즘에만 사용될 수 있다.
사이버 보안 애플리케이션 수가 점점 증가함에 따라 많은 ECU에서 비밀 키, 개인/공용 키 페어 및 인증서 같은 대량의 암호화 자료가 안전하게 저장돼야 할 필요성이 대두되고 있다. 이러한 맥락에서 키 저장과 차량 키 관리에 대한 개념이 종종 사용된다. 키 저장과 차량 키 관리 개념 간 차이점은 아래에서 설명한다.
암호화 키를 안전하게 저장하기 최근 몇 년 동안 사이버 보안에 대한 표준화가 발전했다. 마이크로컨트롤러의 특수 하드웨어 장치인 HSM(하드웨어 보안 모듈)을 사용하면 키를 안전하게 저장하고, 암호화 계산 속도를 높일 수 있다. AUTOSAR 컨소시엄은 키를 모델링하고, 암호화 스택을 사용하기 위해 베이직 소프트웨어 내의 암호화 스택을 표준화했다[2](그림 1).그리고 소프트웨어 기반 라이브러리 또는 HSM에서 제공하는 보안 기능 액세스용의 표준화된 인터페이스를 제공한다(그림 2).이러한 소프트웨어와 하드웨어의 조합을 통해 ECU에 키 자료를 효율적이고, 안전하게 저장할 수 있다.
그림 1|AUTOSAR 암호화 스택의 목적은 키를 모델링해 암호화 서비스를 사용하는 것이다.
그림 2|하드웨어 보안 모듈(HSM)의 아키텍처
암호화 키의 라이프 사이클 차량에서 키의 사용은 일반적인 일상 작동 모드로 제한되지 않는다. 키 관리에 대한 주제 또한 다음의 차량 라이프 사이클 단계에서 고려돼야 한다(그림 3).
1. ECU 개발: ECU에 초기 키를 저장한다. 2. 차량 통합: 초기 키를 개발 키로 대체한다. 3. 차량 생산: 초기 또는 개발 키를 생산 키로 대체한다. 그리고 종종 외부 소스의 다른 키 자료를 설치하거나 해당 차량에 존재하는 키로부터 다른 키 자료를 얻어야 한다. ECU 간에 비밀 키가 공유될 경우 이러한 키의 기밀성과 무결성은 항상 보장돼야 한다. 예를 들어, 비밀키는 버스를 통해 일반 텍스트로 결코 전송되서는 안 된다. 4. A/S와 서비스 해제: 추가 키 자료 업데이트 또는 설치는 원격 기능 활성화에도 적합한 새 키가 필요할 때에 요구될 수 있다. 또한, 결함이 있는 ECU를 교체할 경우 결함이 있는 ECU에서 어떠한 방법으로도 중요한 키 자료를 읽거나 조작할 수 없도록 조치를 취해야 한다. 그리고 기능이 실행될 수 있도록 새 ECU에 적합한 키 자료가 제공돼야 한다.
그림 3|전체 차량 라이프 사이클 동안 키를 관리한다.
키 관리 전략 다양한 키 관리 전략을 잘 보여주는 적용사례는 SecOC이다. SecOC은 ECU 간 차량 내 통신을 검증하는 데 사용된다. SecOC는 메시지 수신자에게 기록된 메시지의 재생을 감지하고, 메시지 발송자의 신뢰성을 확인하고, 전송된 데이터의 무결성을 평가하는 기능을 제공한다. 이를 위해 수신자는 MAC(메세지 인증 코드)라고 알려진 암호화 체크섬을 확인한다. MAC은 기본적으로 발송자가 생성하고 수신자가 유효성을 확인하는 데 사용된다. MAC 확인이 실패하면 수신자는 메시지를 거부한다. 성능상의 이유로 대칭 암호화 알고리즘을 MAC를 계산하는 데 사용한다.
이러한 방법에서 메시지 발송자와 모든 수신자는 MAC를 생성 및 확인을 위해 같은 키를 사용한다. 이 키는 전체 라이프 사이클 동안 기밀이 유지돼야 한다. 따라서 내부 차량 네트워크 또는 차량 외부의 네트워크를 통해 보호되지 않는 상태로 메시지가 전송되서는 안 된다. 다음 예제의 핵심은 생산하는 동안 키 생성 및 설치이다. 이러한 다른 전략은 본 문서에는 평가되지 않지만 유스케이스가 같을 경우에도 실제로는 키 관리에 대한 다른 많은 솔루션이 있음을 알 수 있다. 이 예제에서는 키 자료는 SecOC를 위해 생성 및 배포된다.
오프보드에서 생성된 키 한 가지 전략은 SecOC에 필요한 키를 생성하는 오프보드 키 관리 서버를 보유하는 것이다. 오프보드 키 관리 서버에는 차량에 설치된 ECU에 대한 정보와 SecOC 키에 대한 요구사항이 포함돼 있어야 한다. ECU는 차량이 생산되는 동안 필요한 키를 가져온다. 이들 키는 기밀이므로 전송하는 동안 암호화를 통해 보호돼야 한다. 수신 ECU에서는 키를 저장하기 전에 키의 신뢰성과 무결성을 확인한다.
코디네이터가 있는 상태에서 온보드에서 생성된 키 이 전략의 경우 생산 과정 동안 테스터에서 SecOC 키가 생성될 수 있도록 인증된 요청을 만들어 생성하고, 조정을 담당하는 ECU에 전송한다. 첫 번째 단계에서 조정 담당 ECU는 일반적인 자동차별 키를 생성한다. 그리고 이 ECU는 각 대상 ECU에 임시 보안 연결을 설정하기 위해 키 계약 프로토콜을 사용하고, 미리 생성된 키를 전송한다. 이 키와 키 파생 규격에 기초하여 각 대상 ECU는 적합한 SecOC 키를 생성한다. 키 계약 프로토콜은 다소 긴 실행 시간이 필요하므로 키를 생성 및 배포하는 데에만 사용된다. 모든 대상 ECU는 방금 생성된 키를 사용하여 SecOC를 통해 서로 안전하고, 효율적으로 통신한다. 그리고 모든 대상 ECU는 새 키를 배포하지 않고 이러한 작업을 수행한다.
코디네이터 없이 온보드에서 생성된 키 또한 여기에서 SecOC의 주요 자료가 온보드에서 생성된다. 하지만 키 생성 요청은 조정 기능 담당 ECU에 전송되지 않고, ECU 그룹에 직접 전송된다. 개별 ECU는 그룹의 구성원을 인지하고, 여러 단계의 키 계약 프로토콜을 시작한다. 그룹 구성원은 버스를 통해 이 키를 실제로 전송하지 않고 공유된 키가 생성되도록 메시지를 교환한다. 그룹의 모든 ECU가 공유된 키를 계산하자마자 각 그룹 구성원은 키 파생 규격에 기초하여 필요한 SecOC 키를 생성한다.
표준화 상태 이전에는 키 관리에 대한 표준이 없었지만 솔루션이 필요했으므로 자동차 OEM은 개별 접근 방식을 따랐다. 같은 유형의 문제를 해결하기 위해 이러한 다른 접근 방식을 개발 및 유지관리하면 관련된 모든 이해 당사자에게 추가 비용이 발생한다. 또 다른 고려사항은 키 관리가 일반적으로 경쟁적이고, 차별화된 제품 특성이 아니라는 점이다. 이러한 최적화의 가능성은 AUTOSAR 4.4 Security Extensions에서 인식돼 활용됐다. 키 관리 전용 모듈 KeyM[3]이 지정되었다(그림 4).이 모듈은 두 개의 하위 모듈인 암호화 키와 인증서로 구성돼 있다.
암호화 키 하위 모듈은 협상 키에 필요한 기능을 제공한다. 이러한 프로세스는 다른 단계로 세분화된다. 마지막 단계에서 키 자료는 ECU의 HSM에서 암호화 스택을 통해 파생 및/또는 저장될 수 있다. 위에서 설명한 문제로 인해 자동차 OEM에서 정의하는 논리가 KeyM 모듈에 구현되지 않는다. 대신 키 Key Handler(키 처리기)라는 소프트웨어 구성요소에 구현된다(그림 4). 인증서 하위 모듈은 인증서 구문 분석, 확인 및 설치 기능을 제공한다. 애플리케이션에서 추가 처리를 위해 인증서의 정의된 요소 값을 읽을 수 있다. 마지막 단계에서 인증서는 ECU의 NVM(비휘 발성 메모리) 또는 HSM에 저장된다.
그림 4|AUTOSTAR에서 키 관리는 두 개의 하위 모듈 암호화 키와 인증서가 포함돼 있는 KeyM 모듈에서 구현된다.
표준화의 문제 키 관리는 OEM과 공급업체의 개발, 생산 및 A/S 프로세스와 밀접하게 연관돼 있다. 몇몇 기능에 대한 키 자료가 최근 몇 년 동안 이미 사용돼 왔고, 공개 키 인프라(PKI) 및 키 서버 같은 일부 IT 인프라가 이미 존재한다. OEM은 기존 인프라를 재사용하는 경향이 있으므로 표준화 가능성은 제한된다. 기존의 또는 계획된 인프라 또한 암호화 키를 생성하기 위해 온보드 또는 오프보드 방법을 선택할지 여부에 영향을 미친다. 그리고 키 관리 또한 자동차 OEM이 정의하는 보안 목표의 영향을 받는다. 이러한 목표는 개발, 생산 및 서비스 환경의 보안에 대한 가정 같은 다양한 요소에 기초한다. 예를 들어 사내 생산 환경이 안전하다고 가정할 수 있는지에 대한 의견차가 발생한다. 이러한 가정은 생산하는 동안 그리고 A/S 시 보호 조치에 직접적인 영향을 미친다.
생산력 요구사항 또한 키 관리에 영향을 미친다. 예를 들어 모든 차량의 ECU의 키를 전송하는 데 몇 초만 사용할 수 있을 경우 키 관리 전략을 새로 설계해야 한다. 표준화 시 발생한 변형의 수 감소 암호화 알고리즘과 관련 키 자료는 차량의 최신 보안 메커니즘의 기초를 형성한다. 이러한 알고리즘은 사이버 공격에 대비하여 혁신적인 기능과 기존의 비즈니스 모델을 보호하는 데 사용된다. 표준화를 향한 초기 단계는 AUTOSAR 4.4에 도입된 KeyM 모듈이다. KeyM 모듈은 특정 키 관리 전략을 표준화하지 않고, 다양한 전략 구현에 필요한 일반적인 인터페이스를 제공한다. 자동차 커뮤니티는 키 관리 전략을 조화시키는 데 더욱 집중해야 한다. 이를 통해 관련 전략의 키 처리기를 표준화해 실질적으로 변형의 수를 감소시킬 수 있다. 그리고 높은 수준의 표준화로 비용과
참고문헌 [1] AUTOSAR 4.3 WP-X-SEC (2016), Requirements on Module Secure Onboard Communication [2] AUTOSAR 4.3 WP-X-SEC (2016), Requirements on Crypto Stack [3] AUTOSAR 4.4 WP-X-SEC (2018), Specification of Key Manager
에두아르드 메츠커(Eduard Metzker) 벡터의 사이버 보안 솔루션의 프로덕프 매니저. MICROSAR 베이직 소프트웨어의 보안 메커니즘을 정의했다. AUTOSAR의 수많은 보안 메커니즘을 정의한 AUTOSAR 4.4 Security Extensions 컨셉 그룹을 이끌고 있다. 팔코 K. 바프(Falco K. Bapp) 벡터의 하드웨어 보안 모듈용 소프트웨어인 vHSM의 프로덕트 매니저. vHSM의 아키텍처와 기능 범위를 정의했다. 안토니오 알메이다(Antonio Almeida) 보안 거버넌스 영역의 프로덕트 매니저. 자동차 보안 표준의 개발 프로세스 적합성을 관리한다.