일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | ||||||
2 | 3 | 4 | 5 | 6 | 7 | 8 |
9 | 10 | 11 | 12 | 13 | 14 | 15 |
16 | 17 | 18 | 19 | 20 | 21 | 22 |
23 | 24 | 25 | 26 | 27 | 28 | 29 |
30 | 31 |
- 정보보안
- 코딩
- hackthissite
- 개발자
- write up
- 웹해킹
- Wargame
- 사이버보안
- 테크트렌드
- pythonprogramming
- webhacking.kr
- lord of sqlinjection
- system hacking
- 웹해킹 기초
- Over The Wire
- burp suite
- 인공지능
- Bandit
- web-server
- SQL Injection
- sql injection bypass
- overthewire
- CTF
- WebHacking
- geminipro
- XSS GAME
- web hacking
- root me
- 웹개발
- 프로그래밍
- Today
- Total
컴맹에서 컴공 그리고 화이트 해커가 되는 그날까지
pwnable.kr [collision] write up 본문
2번째 문제 collision을 풀어보았다.
collision의 뜻이 충돌, 격돌이라는 뜻이라고 한다.
ls 명령어를 사용하여 보니 [fd]와 마찬가지로 col col.c flag 3개의 파일이 존재했고
cat flag 역시 권한이 없어 실행하지 못했다.
vi를 사용해 col.c를 살펴보았다.
chat gpt가 있어 공부하기 너무 수월해졌다는 생각이 드는 요즘이다...ㅎㅎ;
일단 hashcode = 0x21DD09EC라고 한다.
그리고 check_password 함수가 보이는데
const char* p: p로 전달된 패스코드를 입력으로 받습니다. const 키워드는 함수 내에서 입력된 문자열을 변경하지 않음을 나타냅니다.
int* ip = (int*)p;: p는 문자열 포인터인데, 이를 정수 포인터로 형변환합니다. 이렇게 하면 패스코드 문자열을 정수 배열처럼 다룰 수 있게 됩니다. 패스코드는 20바이트의 문자열이므로, 이를 4바이트 정수로 쪼개서 다룹니다. 이때, ip는 첫 번째 정수를 가리키는 포인터입니다.
int i;: 루프에서 사용할 변수 i를 선언합니다.
int res = 0;: 결과를 저장할 변수 res를 초기화합니다. 이 변수는 패스코드 문자열을 정수로 변환한 값들을 누적하여 저장할 것입니다.
for(i = 0; i < 5; i++): i를 0부터 4까지 5번 반복합니다. 이는 패스코드 문자열을 5개의 4바이트 정수로 쪼개서 처리하기 위함입니다.
res += ip[i];: 현재 ip가 가리키는 정수를 res에 더합니다. 즉, 패스코드 문자열을 정수로 변환하여 더하는 것을 반복합니다.
return res;: 루프가 완료되면 res에는 패스코드 문자열을 정수로 변환한 값들의 합이 저장되어 있습니다. 이 합을 반환합니다.
main 함수를 보자
명령줄 인자 확인:
if(argc < 2): 프로그램이 실행될 때 명령줄 인자의 개수가 2보다 작으면 (프로그램 이름만 입력되었을 경우) 사용법을 출력하고 프로그램을 종료합니다.
if(strlen(argv[1]) != 20): 입력된 패스코드의 길이가 20바이트가 아니면 패스코드 길이가 잘못되었다는 메시지를 출력하고 프로그램을 종료합니다.
패스코드 검증:
if(hashcode == check_password(argv[1])): 입력된 패스코드를 check_password 함수를 사용하여 확인하고, 이 패스코드의 해시값이 hashcode와 같으면 올바른 패스코드로 간주합니다.
올바른 패스코드인 경우, "/bin/cat flag" 명령을 실행하여 "flag" 파일의 내용을 출력합니다.
오류 처리:else
printf("wrong passcode.\n");
올바른 패스코드가 아닌 경우 "wrong passcode." 메시지를 출력합니다.
즉 이 문제는 20byte로 받은 매개변수를 4byte씩 쪼개서 res라는 반환값을 주는 함수 check_password에 입력값을 넣어 그 값이 hashcode인 0x21DD09EC와 같다면 system("/bin/cat flag"); 가 실행되는 문제이다.
5개의 합이 0x21DD09EC가 되기 위한 값을 찾아보면
0x21DD09EC = 0x6c5cec8 x 4 + 0x6c5cecc로 나타낼 수 있다.
0x21DD09EC를 5로 나누고 나머지를 하나에 더해주면 된다. 가장 간단한 방법!!!
그럼 이제 실행할 명령어를 입력해 보면
./col `python -c 'print "\xc8\xce\xc5\x06"*4+"\xcc\xce\xc5\x06" ' ` 이렇게 입력할 수 있다.
이때 16진수를 리틀엔디안을 사용해서 입력하는 게 포인트이다!
*리틀 엔디안*
리틀 엔디안(Little Endian)은 컴퓨터 아키텍처에서 사용되는 바이트 순서(Byte Order) 중 하나입니다. 바이트 순서란 메모리나 데이터 버스 상에서 여러 바이트로 나누어진 데이터를 어떤 순서로 저장하고 전송하는지를 나타내는 방식을 의미합니다. 리틀 엔디안은 주로 x86 아키텍처 및 일부 기타 아키텍처에서 사용됩니다.
리틀 엔디안 바이트 순서의 특징은 다음과 같습니다:
낮은 주소부터 시작: 리틀 엔디안에서는 데이터의 최하위 바이트(가장 오른쪽에 있는 바이트)가 가장 낮은 주소에 저장됩니다. 다시 말해, 메모리 상의 주소값이 증가함에 따라 데이터의 낮은 바이트부터 순서대로 저장됩니다.
네트워크 바이트 순서와 다름: 리틀 엔디안은 네트워크 바이트 순서(Big Endian)와 반대되는 방식입니다. 네트워크 바이트 순서는 데이터 통신에서 주로 사용되며, 가장 높은 바이트부터 저장됩니다.
예를 들어, 32비트 정수 0x12345678을 리틀 엔디안에서 메모리에 저장하면 다음과 같이 됩니다:
makefile
Copy code
주소: 0x00 0x01 0x02 0x03
데이터: 78 56 34 12
위의 예시에서 보듯이, 가장 낮은 주소(0x00)에서부터 시작하여 데이터의 낮은 바이트부터 저장됩니다.
리틀 엔디안과 네트워크 바이트 순서 간의 변환은 데이터를 다른 엔디안 방식으로 인코딩하거나 디코딩할 때 필요할 수 있습니다. 많은 컴퓨터 아키텍처와 프로그래밍 언어에서는 엔디안 변환을 수행하는 함수 또는 라이브러리가 제공됩니다.
'해킹 > System hacking' 카테고리의 다른 글
🔍 C 언어 포인터와 메모리 보안: 실전 가이드 (0) | 2025.02.19 |
---|---|
pwnable.kr [bof] write up (11) | 2024.09.16 |
pwnable.kr [fd] write up (0) | 2023.09.09 |