리눅스 기반 시스템의 기본 바이너리 형식인 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 기법도 발표되긴 하였으나 난이도가 더 높다.
솔라나는 최근 아주 각광받는 레이어1 코인입니다. 일단 gas fee가 이더리움에 비해 압도적으로 저렴하고, PoH라는 새로운 접근 방식을 통해 초당 트랜잭션 수도 아주 뛰어나 무려 초당 5만 개에 달하는 트랜잭션을 처리할 수 있습니다. 기존 비트코인, 이더리움의 초당 10여 개에 불과한 트랜잭션 수와 비교하면 아주 장족의 발전이죠.
트랜잭션의 gas fee도 현재 5000Lamport (0.000000001SOL) 에 불과해 20만원이 1솔라나라고 가정하면 트랜잭션당 소모되는 gas fee가 10원에 불과합니다. 해외 송금 해보신 분들은 아실거에요. 이 수치가 얼마나 대단한 것인지... 순식간에 이체되고, 아주 적은 비용으로 송금이 가능합니다.
솔라나는 당연히 최신 기술인 NFT 민팅과 Smart Contract, Defi 등을 지원합니다. 이번 글에선, 이 모든 기술들의 근간이 될 스마트 컨트랙트를 빌딩하는 방법에 대해서 알아보려고 합니다.
사실 많은 분들이 스마트 컨트랙트가 뭔지 구체적으로 알지 못하고 계시지만, 개념은 엄청 간단합니다. 그냥 자판기를 생각하시면 됩니다. 내가 어떤 일을 하면 어떤 결과가 나올지 미리 정해진 스크립트에 따라 수행되는 것이죠! 인터넷에 수행될 코드를 미리 업로드시켜놓고, 수행 조건이 만족되면 해당 코드가 자동으로 실행되고 연산됩니다. 이게 답니다!
그럼 이게 왜 혁신적이냐고요? 왜냐면, 기존에는 다들 '신뢰'에 기초해서 하던 작업들을 이젠 딱히 상대를 신뢰하지 않아도 되거든요. 예를 들면 제가 어떤 게임을 하고 이겼을 때 1000원을 받는다고 해봅시다. 종전에는 이 게임을 하고 1000원을 받는 행위 자체를 해당 사이트를 '신뢰'하지 않으면 할 수 없었습니다. 게임 사이트가 나에게 돈을 줄지, 주지 않을지 어떻게 아나요?
하지만 블록체인 스마트 컨트랙트는 다릅니다. 스마트 컨트랙트 온체인에서 일어나는 모든 일들은 스크립트를 읽을 수 있는 능력만 있다면 게임사이트가 특정 조건을 만족하면 자동으로 나에게 돈을 준다는 사실을 알 수 있습니다. 그렇지 않다면, 교묘하게 그렇지 않은 코드를 삽입했다는 사실도 알아낼 수 있죠. 현재는 일부 프로그래머만이 해당 사실을 검증할 수 있겠습니다만, 적어도 모두에게 공개되어있는 코드에 대놓고 스캠 코드를 삽입할 수는 없겠죠?
스마트 컨트랙트에 대한 대략적인 설명입니다. 먼저 프로그램된 컨트랙트 (계약)을 올려놓고, 이벤트가 진행이 되면 해당 이벤트가 실행이 됩니다. 그 실행 내역에 따라서 토큰 (뭐... 돈이죠) 이 오가는 것을 보증할 수 있습니다.
borsh는Binary Object Representation Serializer for Hashing 의 약어입니다. 바이너리로 풀어진 오브젝트를 시리얼라이징하거나 디시리얼라이징할 때 쓰이는 일종의 라이브러리라고 생각하시면 됩니다. node에도 동일하게 존재하는 라이브러리입니다.
entrypoint!() 에서 실제 스마트 컨트랙트가 선언되는데, 이 안 내용을 한번 살펴보시죠.
account.iter()는 map과 비슷한겁니다. account를 iterable하게 돌려서 account를 하나씩 살펴본다는 의미입니다. 그래서 next_account_info로 account를 가지고 온 후, 해당 account_info에 데이터를 set해줄 준비를 할 겁니다. 데이터를 저장해야 그 데이터로 무언가 로직을 돌릴테니, 이번 예제에선 데이터를 저장하는 로직만 해볼거에요. 그러니까... UPDATE, INSERT, SELECT 세 기능을 구현해 볼 겁니다.
여기가 핵심 로직인데요, account의 data를 가지고 와서, instruction_data를 해당 data에 set 해주는 부분입니다. instruction_data는 우리가 직접 넣어주는 데이터가 될 거에요. 그 다음 다시 저장해주고 Ok() 해주면, 해당 노드 블럭에 스마트 컨트랙트 내용이 저장됩니다.
`Failed to read program keypair at '${PROGRAM_KEYPAIR_PATH}' due to error: ${errMsg}. Program may need to be deployed with \`solana program deploy dist/program/helloworld.so\``,
이제 실제로 트랜잭션을 발생시킵니다. TransactionInstruction의 input이 아까 러스트랑 동일하죠? 맞습니다, 러스트에서 받는 인자들입니다. 따라서 data에 저렇게 넣으면 2라는 숫자가 들어갑니다. 중요한건, Buffer로 선언된 ㄹㅇ 바이너리 숫자가 들어간다는 사실입니다.
이렇게 솔라나로 아주 간단한 스마트 컨트랙트를 만들어 봤습니다. 노드를 통해 통신할 수 있으니, 아마 노드 웹서버를 통해 통신할 수도 있겠지요.
이런 스마트 컨트랙트를 openDB, open Logic으로도 사용할 수 있습니다. 누구나 볼 수 있는 DB, 그리고 누구나 볼 수 있는 로직이기 때문에 절대로 속일 수 없다는 특징을 가지게 된 것이죠. 누구나 검증할 수 있게 된 것입니다. 물론, 스마트컨트랙트를 누구나 발생시킬 수 있기 때문에, 실제 구현상에선 greetedPubKey의 SEED를 적절하게 잘 숨겨서 보관하는 것도 중요합니다. 해당 seed가 곧 DB의 암호가 되는 셈이니까요.
이 글이 한국어 사용자의 스마트 컨트랙트 이해도 향상에 조금이나마 도움이 되었으면 좋겠습니다! 기회가 된다면 다음 글로 곧 스마트컨트랙트의 실제 활용도 한번 보여드리겠습니다.
추가)
사실 프로그램을 만들 때엔 anchor를 이용하시는 것이 좋습니다. 해당 글도 읽어보세요!
통신은 사람이나 사물 간에 매체를 통하여 정보나 의사를 전달하는 것을 말합니다. 자동차 안에는 수많은 부품 및 제어기들이 있습니다. 엔진을 제어하는 ECU (Engine Control Unit), 변속기를 제어하는 TCU (Transmission Control Unit), 각종 ADAS (Advanced Driver Assistance System) 관련 제어기 등 수십 개에 해당하는 제어기들이 차량에 장착되고, 제어기들은 서로 데이터를 주고받으며 공유된 정보를 통해 다양한 제어를 하게 됩니다. 데이터를 주고받을 때 제어기들 간의 규칙이 있어야 원활한 통신을 할 수 있는데, 이러한 규칙을 통신 프로토콜 (Protocol)이라고 합니다. 자동차 내에는 CAN (Controller Area Network) 통신, LIN 통신, LAN 통신 등 다양한 통신 방법을 용도에 맞게 사용하고 있습니다. 그중에서 CAN 통신이 자동차에서 가장 많이 사용되고 있습니다.
CAN 통신은 자동차 부품회사인 보쉬 (BOSCH)에서 개발된 차량용 네트워크 통신 방식으로, 전기적 노이즈 발생이 많은 자동차 환경에서 신뢰성을 확보하기 위해 개발된 통신 방식입니다.
CAN 통신은 여러 개의 제어기들을 병렬로 연결하여 데이터를 주고받는 구조로 되어 있습니다. 통신 라인을 공유하는 모든 제어기들이 마스터 역할을 하고 있기 때문에 필요에 따라 언제든지 통신이 가능합니다. 쉽게 말해, 통신선상에 데이터를 띄워 놓으면, 어떤 제어기든지 필요할 때마다 데이터를 가져가 사용하는 방식입니다.
여러 개의 제어기들을 병렬로 연결하여 데이터를 주고받는 구조
제어기 내부의 CAN 통신 회로 구성
제어기 내의 CAN 통신 회로 구성은 위의 블록도와 같습니다. 가장 오른쪽은 외부 CAN BUS로 CAN H와 CAN L 신호를 주고받습니다. CAN BUS는 제어기 커넥터를 통해 연결된 후 CAN 트랜시버로 연결됩니다. 그리고 CAN 트랜시버는 마이크로컨트롤러 (MCU)와 연결됩니다. 정리하면, MCU와 CAN BUS 사이에 CAN 트랜시버가 있는 구조입니다. 그렇다면 CAN 트랜시버의 역할을 간단하게 살펴보겠습니다.
먼저 CAN H와 CAN L의 파형은 아래 그림의 오른쪽과 같습니다. CAN H는 2.5V~3.5V 전압을, CAN L는 2.5V~1.5V 전압을 사용합니다. CAN H와 CAN L의 전위차가 없을 때는 recessive (열성), CAN H와 CAN L의 전위차가 있을 때는 dominant (우성)이라고 표현합니다. 즉, CAN 통신은 두 라인의 전위차를 통해 데이터를 전달하는 것입니다.
CAN 통신의 Recessive와 Dominant
CAN BUS의 CAN H와 CAN L 신호가 CAN 트랜시버를 통해 recessive 인지 dominant 인지 판단을 합니다. 그리고 CAN 트랜시버의 RX를 통해 recessive 이면 HIGH, dominant 이면 LOW 신호를 MCU에 전달합니다. 반대로 MCU에서 CAN BUS로 데이터를 전송할 때는 MCU의 LOW와 HIGH 신호를 CAN 트랜시버가 CAN H와 CAN L 신호 형태에 맞게 변환해 줍니다.
출처 : TEXAS INSTRUMENTS, Indtroduction to the Controller Area Network (CAN)
CAN 트랜시버 내부 회로도
위의 CAN 트랜시버 회로와 같이, MCU의 TX에서 HIGH 신호를 보내면 FET는 비활성화되어 2.5V 풀업 저항에 의해 CAN H와 CAN L 모두 2.5V가 됩니다. 반대로 MCU의 TX에서 LOW 신호를 보내면 FET는 활성화되어 CAN H 5V, CAN L는 GND 전위가 됩니다.
CAN 프레임 형식에 대해 간단하게 알아보겠습니다. 바로 아래 그림과 같이 CAN 통신에서 요구하는 CAN 통신 프레임을 만족해야 제어기들 간에 데이터를 전송할 수 있습니다. 쉽게 말해, 서로 데이터를 어떻게 주고받을지 약속을 정하는 것과 같습니다.
CAN 프레임 형식
SOF (Start of Frame)
메시지의 시작을 표시, idle 상태 이후 동기화
Identifier
메시지의 우선순위를 설정, 이진값이 낮을수록 우선순위가 높음
RTR (Remote Transmission Request)
데이터 프레임과 리모트 프레임 구분 (데이터 프레임은 0)
IDE (Idenrifier Extension)
CAN Standard 프레임과 CAN Extended 프레임 구분
R0
Reserved bit
DLC (Data Length Code)
전송 중인 데이터의 바이트 수
Data
8byte 데이터를 전송
CRC (Cycle Redundancy Check)
16bit checksum
ACK (Acknowledgement)
승인
EOF (End of Frame)
CAN 프레임의 끝을 표시
IFS (Interframe Space)
버퍼 영역
CAN 통신은 여러 제어기들이 신호를 함께 보내고, 이를 피드백 받으면서 진행됩니다. 하지만 동시에 여러 제어기들이 신호를 송신한다면 어떻게 우선순위를 정하는지 알아보겠습니다. 아래 표와 같이 NODE 3를 가지고 Idendifier의 비트를 비교합니다.
CAN 통신 arbitration의 원리
신호가 HIGH 이면 recessive, LOW 이면dominant 입니다. 위의 그림에서 10~6 bit 까지 3개의 NODE 상태는 모두 동일합니다. 5번 bit는 NODE 2만 HIGH (recessive)입니다. Recessive는 말 그대로 "열성"이라는 의미로 여기서부터 NODE 2의 신호 전송은 중지됩니다. 그리고 2번 bit에서는 NODE 1이 HIGH (recessive)입니다. 따라서 NODE 1의 신호 전송이 중지됩니다. 결국 여기서 우선순위는 NODE 3이 가장 높습니다. 중간에 전송을 중지한 NODE 1과 NODE 2는 다음에 재전송을 시도합니다.
※ CAN 통신에서의 에러
에러가 발생되면 에러 프레임이 전송됩니다. 에러 프레임으로 전송 실패를 인식하면 재전송의 기회를 기다립니다.
- BIT 에러 : 송신 bit와 수신 bit가 상이한 경우
- ACK 에러 : 수신 장치가 응답이 없을 때, 통신 선로가 끊기거나 접촉 불량인 경우
- FORMAT 에러 : CRC del, ACK del, EOF 영역에 0 (dominant) 값이 나타난 경우
- STUFF 에러 : Stuffing 규칙이 맞지 않은 경우
- CRC 에러 : CRC가 맞지 않은 경우
CAN 제어기 내부에는 송신 에러 카운터와 수신 에러 카운터가 각각 있습니다. 에러가 검출될 때마다 카운터가 1씩 증가하고, 에러 없이 성공적으로 전달이 완료되면 카운터가 1씩 감소합니다. 초기 상태에는 Error active 상태이며, 에러 카운터 값이 127 보다 커지면 Error passive 상태가 됩니다. 그리고 에러 카운터 값이 255를 초과하면 BUS OFF 상태로 해당 노드를 CAN 망에서 끊어버립니다.
The File Transfer Protocol (FTP) is a standard network protocol used for the transfer of computer files between a client and server on a computer network. It is a plain-text protocol that uses as new line character 0x0d 0x0a so sometimes you need to connect using telnet or nc -C.
Default Port: 21
PORT STATE SERVICE
21/tcp open ftp
Connections Active & Passive
In Active FTP the FTP client first initiates the control connection from its port N to FTP Servers command port – port 21. The client then listens to port N+1 and sends the port N+1 to FTP Server. FTP Server then initiates the data connection, from its port M to the port N+1 of the FTP Client.
But, if the FTP Client has a firewall setup that controls the incoming data connections from outside, then active FTP may be a problem. And, a feasible solution for that is Passive FTP.
In Passive FTP, the client initiates the control connection from its port N to the port 21 of FTP Server. After this, the client issues a passv comand. The server then sends the client one of its port number M. And the clientinitiates the data connection from its port P to port M of the FTP Server.
Anon login and bounce FTP checks are perform by default by nmap with -sC option or:
nmap --script ftp-* -p21<ip>
Browser connection
You can connect to a FTP server using a browser (like Firefox) using a URL like:
ftp://anonymous:anonymous@10.10.10.98
Note that if a web application is sending data controlled by a user directly to a FTP server you can send double URL encode %0d%0a (in double URL encode this is %250d%250a) bytes and make the FTP server perform arbitrary actions. One of this possible arbitrary actions is to download content from a users controlled server, perform port scanning or try to talk to other plain-text based services (like http).
Download all files from FTP
wget-m ftp://anonymous:anonymous@10.10.10.98 #Donwload all
wget-m --no-passive ftp://anonymous:anonymous@10.10.10.98 #Download all
Some FTP commands
FTPBounce attack
Some FTP servers allow the command PORT. This command can be used to indicate to the server that you wants to connect to other FTP server at some port. Then, you can use this to scan which ports of a host are open through a FTP server.
You could also abuse this behaviour to make a FTP server interact with other protocols. You could upload a file containing an HTTP request and make the vulnerable FTP server send it to an arbitrary HTTP server (maybe to add a new admin user?) or even upload a FTP request and make the vulnerable FTP server download a file for a different FTP server. The theory is easy:
Its highly probably that this will throw an error likeSocket not writablebecause the connection doesn't last enough to send the data with RETR. Suggestions to try to avoid that are:
FileZilla usually binds to local an Administrative service for the FileZilla-Server (port 14147). If you can create a tunnel from your machine to access this port, you can connect to it using a blank password and create a new user for the FTP service.
Config files
ftpusers
ftp.conf
proftpd.conf
vsftpd.conf
Post-Exploitation
The default configuration of vsFTPd can be found in /etc/vsftpd.conf. In here, you could find some dangerous settings:
SBOM 은 SOFTWARE BILL OF MATERIALS 의 약자로 소프트웨어의 구성 요소를 나타내는 메타데이터를 의미하는데 이를 보다 쉽게 설명하자면 우리가 흔히 볼 수 있는 다음과 같은 제품의 성분표기를 떠올리면 됩니다.
성분표기를 통해서 알러지가 있는 사람은 해당 식품을 피하기도 하고, 공급자는 제품의 우수성을 홍보하기도 하고, 크게 성분에 신경쓰지 않고 그냥 사용하는 사용자도 있을 수 있죠.
이와 유사하게, SBOM은 공급되는 소프트웨어의 구성 목록을 잘 표시해서 공급자와 사용자가 이를 기반으로 의사결정에 활용할 수 있는 환경을 조성하는 것을 목표로 하고 있습니다.
NTIA 에서 발표한 SBOM의 필수 구성요소는 다음과 같이 구성되어 있습니다.
Supplier name
Component name
Version of the component
Cryptograph hash of the component
Any other unique identifier
Dependency relationship
Author of the SBOM data
이를 기반으로 작성한다면 다음과 같은 개념도로 표시할 수 있습니다.
National Telecommunications and Information Administration (NTIA) 에서는 오픈소스 소프트웨어나 상용 소프트웨어로 구분하지 않고 모든 공급되는 소프트웨어를 대상으로 광범위하게 적용할 수 있는 SBOM 적용을 위해 산업계의 여러 기업과 커뮤니티에 의견을 청취하고 이를 토대로 SBOM의 이해를 돕는 자료와 적용방법에 대하여 다양한 문서를 배포하고 있으니 아래 문서들을 참고하시기 바랍니다.
SBOM이 소프트웨어 보안의 모든 문제를 해결할 수는 없지만 보다 안전한 소프트웨어 사용에 필요한 기본을 제공하는 것은 분명히 필요한 일이며, 다양한 산업계의 의견을 토대로 만들어진 SBOM을 기반으로 소프트웨어 공급망의 투명성을 강화할 수 있는 미국의 이번 정책은 향후 IT 산업과 디지털 인프라의 소프트웨어 관리에 있어서 매우 중요하다고 생각됩니다.
Years ago, a team of researchers at SUTD (Asset-Group) discovered and disclosed the family of vulnerabilities in the classic Bluetooth link manager layer. They've released a paper and POC named "Braktooth: Causing Havoc on Bluetooth link manager" The paper is very detailed and enjoyable to read. I highly recommend it to anyone into Bluetooth security. The Braktooth is a codename for 16 classic Bluetooth vulnerabilities. It will cause affect BT devices continuously crash or deadlock. Furthermore, at least in one case, attackers can remotely execute arbitrary code and erase all the data on the targeted devices. These bugs are present in various BT Chipsets across many manufacturers such as Intel, Qualcomm, TI, Infineon, etc.
Since my main interest focused on vehicle security, after reading through the Braktooth paper, one thing immediately got my attention. They mentioned in the paper, Braktooth not only affects laptops, and smartphones but also Infotainment units in Automobiles, even the audio system in airplanes is affected. For IVIs, they listed the Volvo FH as an example in the paper. This got me wondering if any other popular cars out there are also affected by Braktooth.
FIRST-BLOOD
Before we jump on the cars, we need to get familiar with Braktooth. The actual environment is quite simple to set it up. In the paper, they mentioned some Chipset from Mediatek that are affected. My laptop Lenovo L14 happened to use the Ralink chipset for Bluetooth communication. Since Ralink is part of the Mediatek group, which make it is the perfect target for the test run.
Because there are 16 POCs from the Braktooth vulnerabilities, we've to go through all of them. And we found one of the vulnerabilities called Invalid-Timing-Accuracy almost always work. The vulnerable chipsets do not properly handle the reception of a malformed LMP timing accuracy response followed by multiple re-connections to the target link slave.
This allows attackers to exhaust device BT resources. The attacker can trigger a crash or disturb other BT devices connected to the target chipset. The best part is attacker only needs to know the BDAddress of the target device. No authentication is required to launch the attack. As the video below demonstrated, the Bluetooth connection between the laptop and speaker stop functioning and eventually disconnected the connection.
INVESTIGATION
People always ask us how can Star-V Lab access so many cars. And this project is a perfect chance to show how we achieved it. The easiest place to start would be for the Car components to sit on the test bench table. For example, we happened to have a 2nd hand Nissan IVI in the lab. As we can see, after we fired the Invalid-Timing-Accuracy POC, the Nissan IVI kind of frozen, and it won't detect any Bluetooth devices nearby anymore.
The 2nd place to look for potential targets is the company car parking lot. If we ask nicely, most of the staff even the company CEO are interested to see if their car can hacked ;) At that time, we got 2 Tesla cars and 1 Changan Uni-T accessible for testing. For Tesla Model 3 and Model X, only the Invalid-Setup-Complete POC worked. All other POCs failed.
But for Changan Uni-T almost all the vulns works. Only 6 of the POC has no impaction. As the video shows, Braktooth disconnected the connection. Interestingly the Bluetooth logo on the IVI screen still shows everything is fine, but in fact, the connection has been disconnected.
If we got enough budget we can rent some cars for testing. But what if our budget is short and we need to test the latest modern cars? An advantage of living in a big city is we are surrounded by Car dealer shops. And these are perfect spots for us.
This time we found 4 cars affected by Braktooth. The first one is NIO ET5, which is a Chinese brand and quite popular in China.
For NIO it will disconnect the Bluetooth connection straight away.
Then we went to the Volkswagen to test ID4X. Compare to other Android-based IVI, ID4X seems a bit hard to use.
Again once we fired the attack, the Bluetooth connection disconnected.
Finally, we tested a new smart car player in the Chinese market called ARCFOX. As the video shows the music start been funny after we fired the attack.
One thing special regarding this brand is one of the car models using the Huawei HarmonyOS as IVI's system.
However, when coming to low-level Bluetooth attack, Huawei HarmonyOS makes no difference.
Another nice spot for testing is the Car exhibition. The good thing about the exhibition is we may able to test some fancy sports cars, which normally we won't be able to touch.
Here we've tested the Neta V and Leapmotor C01 cars.
As we can see both of them experienced the disturb first then the connection disconnected completely.
FINAL-FHOUGHT
As whitehat security researchers, we like to follow the responsible disclosure procedure. Unfortunately unlike the Internet companies, most car companies still live in a stone age. They neither don't have a bounty program nor contact info for reporting bugs. Therefore, we filed a report to their customer service and hope someone can see it. But we like to give a thumbup to the Tesla and NIO. These two companies have set up bug bounty programs and given a very quick response to our bug report. However, Nio replied that this bug has out of their scope.
And Tesla thinks this is not a security issue, since the braktooth was only able to cause the Tesla Bluetooth audio jitters. We kind of agreed on this point, so let's continue our journey and digging deeper. Spoiler alert, we did find other issues on some of those IVIs above. And at least caused one of the fancy car's IVI to go black screen. Stay tuned for our future report ;)
Once the device is on and plugged in, it wakes up the CAN network by sending a frame—similar to if you were to pull on a door handle, approach with a passive entry key, or hit a button on your fob. It then listens for a specific CAN message to begin its attack. The device then emulates a hardware error which tricks other ECUs on the CAN network to stop sending messages so that the attacking device has priority to send its spoofed messages to CAN devices.
The pause of valid messages is when the device is able to go into attack mode. It then sends the spoofed "valid key present" messages to the gateway which makes the car think that an actual valid key is being used to control the vehicle. Next, the attacker simply presses the speaker's "play" button, and the car's doors are unlocked.
Given that the manufacturer of these CAN injection devices claims that the devices are so effective against a myriad of makes and models, it would seem that this could be an industry-wide problem that may take some brainstorming to fix.
The good news is that this type of attack can be thwarted. While there are quick-and-dirty methods that could potentially be re-defeated in the long run, an automaker looking to prevent this type of attack by encrypting its CAN Bus network. According to Tindell, Canis is working on a similar project to retrofit U.S. military vehicles with a similar encryption scheme, similar to what he suggests as the fix for commercial vehicles experiencing this issue.