728x90

gdb --args
디버깅할 프로그램에 직접 파라미터를 제공 (잘 모르겠음)

thread apply all bt
모든 스레드에 대해 백트레이스 정보를 덤프한다

gdb --batch --ex r --ex bt -e-x q --args
실행중인 프로그램이 죽을 때 벡트레이스 정보를 얻도록 한다.

run [args]
디버깅할 프로그램을 파라미터[args]와 함께 실행시킨다.

break (b)
함수에 중단점 설정

backtrace
현재 호풀 스택에 대한 백트레이스 덤프(bt)

print expr
expr값 출력

continue
프로그램 계속 실행

next
다음 줄까지만 실행, 함수 호출 시 함수 안으로 진입하진 않음

step
다음 줄까지만 실행, 함수 호출시 함수 안으로 진입

clear
중단점을 지운다

info break
중단점 정보를 보여준다

attach pid
실행 중인 프로세스를 붙여 디버그할 수 있도록 한다.

detach
프로세스 분리

list
소스코드 10줄 보여줌

728x90

'Linux system' 카테고리의 다른 글

Linux 시스템에 대한 이해 _ 2  (0) 2021.04.10
Linux 시스템에 대한 이해 _ 1  (0) 2021.04.09
728x90

배열 : 같은 데이터형 변수를 메모리에 연속적으로 할당함

ex) arr[3] : arr[0], arr[1],arr[2]

  • 배열 선언시 타입에 따라 메모리에 할당

    ex) int arr[3] : 4byte * 3 = 12byte

    ​ char arr[3] : 1byte * 3 = 3byte

  • 배열 초기값 지정 시 크기보다 부족하게 지정될 경우, 나머지 배열의 값은 0으로 초기화 (초기값보다 많이 할 경우 당연히 에러)

  • 초기값을 지정하는 경우, 배열의 크기선언은 생략 가능, 다만 선언된 크기만큼만 지정된다.

  • 배열에 다른 배열을 대입은 항상 불가능, 하기 위해선 1대1 대응만 가능

  • int arr[3]을 선언할 경우 변수 arr에는 arr배열의 주소가 들어가있다.

2차원 배열 : 행(row), 열(column) 순서로 들어감

int scores[5][3]

학생번호 중간고사 기말고사 과제
0 score[0][0] score[0][1] score[0][2]
1 score[1][0] score[1][1] score[1][2]
2 score[2][0] score[2][1] score[2][2]
3 score[3][0] score[3][1] score[3][2]
4 score[4][0] score[4][1] score[4][2]
  • 2차원 배열 초기화는 {}안에 {}를 넣어줘야 함

    ex) int data[3][2] = {{10,20},{30,40},{50,60}};

  • 초기화할때 행은 생략 가능

    ex) int w[][3] = {{1,2},{3},{4,5}} | {1,2,0},{3,0,0},{4,5,0}으로 초기화

    ​ int z[][2] = {1,2,3,4,5,6,7} | {{1,2},{3,4},{5,6},{7,0}}으로 초기화

배열을 매개변수로 받아올 때

void print_array(int arr[], int size)
{
    ;
}
int main(void)
{
    int data[] = {1,2,3};
    print_array(data,3);
}

배열의 주소와 크기를 따로 받아오고, main에서 전달할 때 배열의 이름을 전달해줘야 한다. (이름으로 지정된 변수에 배열의 주소가 저장되어 있기 때문) 또한, 당연히 원소형은 일치해야 한다.

728x90
728x90

exe파일과 txt파일 하나씩 있네요. 

이름 입력 형식이 자유니 이름에 따라 serial넘버가 만들어지는것 같네요. 자세한건 디버거로 확인해봅시당

 

v6배열을 확인해보면 0 -> 16, 1 -> 32, 2 -> 48 이렇게 배정되어  있고 루프로 3개씩 반복되니 v7[0] ^ 16, v7[1] ^ 32, v7[2] ^ 48, v7[3] ^ 0x16 이렇게 반복되네요.

sprintf에서 Buffer의 주소와 연산 값을 넣어주고, 입력값(v7)과 string compare한 후에 correct와 wrong으로 분리됩니다.

정적 디버깅으로 코드의 흐름을 대충 알아봤고 이제 동적 디버깅으로 자세히 알아봅시다.

 

우선 연산값을 보기 위해 for문 안에 breakpoint를 하나 걸어주고, 하나하나씩 실행해보며 확인해보겠습니다.

 

우선 첫 변수 name의 입력값은 AAAA로 넣어주었습니다. 입력값이 stack에 잘 들어가는것이 보입니다. 굿

 

 

입력값 "AAAA"의 1번 루프

 

ecx와 edx에 어떤 값을 넣어주는것을 확인할 수 있습니다.

각각 0x10, 0x41이 들어가있습니다. 0x41은 입력값 'A'의 ascii값이고 0x10은 v6[0]값이라고 생각할 수 있습니다. 

또한 다음으로 ecx, edx의 xor값을 ecx에 넣어줍니다. 

잘 들어가있네요 

 

xor된 값을 넣어주고 compare연산 후 루프로 돌아갑니다. 

compare연산은 ebp와 ecx에서 진행하는데 각각 1, 4로 1은 현재 진행한 문자 개수, 4는 총 문자의 개수로 생각할 수 있습니다. 확인은 입력값을 바꿔보면서 할 수 있는데, 과정은 노가다이므로 과감히 생략합니다! 

 

입력값 "AAAA"의 2번 루프

ecx값이 전엔 0x10이였지만 지금은 0x20인 걸 알수있죠. 배열 v6의 값인건 확실합니다. 이후 4번의 루프(입력이 4글자이므로) 끝나고 stack을 확인해보면, 

 

0x0019fe08에 \x42\x42\x42\x42, 즉 "AAAA"가 들어있음을 알 수 있고

0x0019fe6c엔 \x35\x31 (0x51), \x36\x31 (0x61), \x37\x31(0x71), \x35\x31 (0x51) 이 들어가있음을 알 수 있습니다.

(문자열 연산이므로 바이트코드로 들어가지 않아서 ascii로 계산합니다. 뒤에서 2개씩 끊어서 ascii로 변환해보면 값을 알 수 있습니다.)

 

serical을 입력하면 다음과 같은 방식처럼 하나하나 compare연산을 합니다. jnz연산은 총 3번이 있는데 

1, 2번째의 연산은 입력값(serical)과 연산된 값을 비교하는 연산입니다.

(A를 비교한다 하면 A가 ascii값이 0x41이고 4와 1을 하나씩 비교합니다)

3번째 연산은 길이를 계산하여 다하면 루프에서 탈출시켜줍니다. 

 

 

이렇게 연산이 끝나고, correct와 wrong으로 갈라집니다..

 

 

역연산은 어렵지 않습니다. xor은 xor로 상쇄되기 때문이죠! 

 

#include <stdio.h>
int main()
{
	unsigned int arr[8] = { 0x5B,0x13,0x49,0x77,0x13,0x5E,0x7D,0x13 };
	unsigned int ans[8] = { 0 };
	int num[3] = { 16,32,48 };
	int j = 0;
	for (int i = 0; i < 8; i++,j++)
	{
		if (j > 2)
			j = 0;
		ans[i] = arr[i] ^ num[j];
	}
	for (int i = 0; i < 8; i++)
		printf("%c", ans[i]);
}

 

 

 

(ida를 업데이트했더니 아주 이쁘게 잘 분석하네요.  아주 좋아요~)

728x90

'reversing > reversing.kr' 카테고리의 다른 글

[reversing.kr] Replace  (0) 2024.02.16
[reversing.kr] Music Player  (1) 2024.02.15
[reversing.kr] Easy_CrackMe  (0) 2020.11.29
728x90

저번엔 시스템 메모리에 관련된 공부를 했습니다. 오늘은 소프트웨어 관리와 하드웨어 관리, 파일시스템 관리까지 해보겠습니다.

 

소프트웨어 관리

리눅스에서 돌아가는 프로그램을 프로세스(process)라고 합니다. 프로세스는 백그라운드와 포그라운드(foreground)가 있는데, 이를 커널이 관리합니다. 리눅스 커널은 다른 프로세스들을 실행시키기 위한 초기 프로세스를 관리합니다. 초기 실행시 virtual memory에 초기 프로세스를 로드하고 이 프로세스가 다른 프로세스의 data와 code를 저장하기 위한 공간을 배정해줍니다.

 

또한 리눅스엔 초기 실행시 8가지의 권한 설정이 있습니다.

 

level 0

코드나 구조에 에러가 있을 경우 하드웨어 손상을 방지하기 위한 시스템 강제 중지모드입니다. 안드로이드의 은어로는 벽돌이라고도 부르죠. 보통 무한부팅처럼 부트로더를 통과한 후에 나는 에러들은 이 모드로 리턴되는것이 아닙니다.

부트로더가 손상된 경우 이 모드로 리턴하고, 아예 부팅모드로 접근하지 못합니다. (odin모드로는 접근 가능해서 이 모드로 복구를 합니다)

 

level 1 

가장 높은? 권한이라 할 수 있습니다. single-user mode이고 오직 관리자만 접근할 수 있습니다. 안드로이드에선 부트로더 모드라고 할 수 있겠네요. 보통 공장 초기화모드로 들어간다고 하고, 부트로더를 제외한 모든 시스템을 수정할 수 있습니다. 

 

level 2

보통 상태에서 네트워크 연결이 차단된 상태입니다. 안전모드라고 생각하시면 됩니다. 다만 아직은 X windows가 없는 콘솔상태입니다. 바이러스를 찾거나 포렌식을 할때 사용합니다.

 

level 3

level 2 상태에서 인터넷 연결이 있는 모드입니다.

 

level 4 (not used)

 

level 5

아주 가장 일반적인 모드입니다. 여러분들이 사용하시는 우분투는 서버컴이 아닌 이상 다 이 상태입니다.

multiuser와 X windows를 지원합니다. 

 

(X windows는 그래픽으로 3차원? 처럼 표현해주는 소프트웨어입니다)

 

level 6 (reboot the system)

이게 그 골때리는 무한부팅 상태입니다. 

 

참고 문서 

www.tutorialspoint.com/init-process-on-unix-and-linux-systems

 

Init process on UNIX and Linux systems

Init process on UNIX and Linux systems Init is the parent of all processes, executed by the kernel during the booting of a system. Its principle role is to create processes from a script stored in the file /etc/inittab. It usually has entries which cause

www.tutorialspoint.com

 

하드웨어 관리

부채널분석? 관련 공부를 조금 했을때 이부분 공부가 가장 골때렸습니다. 

커널의 역할은 소프트웨어와 하드웨어 사이의 브릿지라고 전에 말했습니당. 어느 장치건 리눅스 시스템에 연결하기 위해선 kernel code 안에 driver code를 삽입해야 합니다. 삽입하는 방법은 2가지가 있습니다. 

1. Drivers compied in the kernel

그냥 해당 드라이버 코드를 삽입한 커널코드를 리컴파일하는겁니다. 커널을 새로 만든다고 할 수 있고, 장비가 많아질수록 비효율적입니다. 매우!

 

2. Driver modules added to the kernel

1번 방법을 사용하다 나온 보완된 방법입니다. 커널 전체를 튀기지 않고 드라이버 코드를 커널에 삽입합니다. 또한 사용이 끝나면 커널에서 제거할 수 있습니다. 이제 대부분의 os들이 이 방법을 사용합니다. 

 

리눅스에서 device들을 Character, Block, Network 이렇게 3가지로 분류할 수 있습니다.  Character 은 모뎀이나 터미널처럼 한번에 한가지의 character 만 다룰 수 있습니다. charater을 번역을 어떻게 해야할지 모르겠슴다 :(

이와 다르게 저장소처럼 여러가지의 character들, 큰 block안에 있는 데이터들을 다룰 수 있는 장치를 Block file이라 부릅니다. 

네트워크 장치는 말 그대로 프로토콜로 소통할 수 있는 기기를 말합니다.

 

이 기기들은 (character, block, network) _(devices) 각각의 특수한 숫자를 가지고 있는 node가 만들어집니다. id card라고 보시면 됩니다. 이렇게 만들어진 node들로 software가 hardware를 사용합니다. (communicate)

 

 파일시스템 관리

 

리눅스의 장점은 여러가지의 filesystem을 지원한다는 것입니다.

 

이 모든 저장소를 VFS(virtual file system)을 이용하여 연결할(interface) 수 있습니다.

 

다음엔 재밌는 GNU Uilities에 대해 알아봅시다 :)

 

참고 서적 -Linux Command Line and Shell Scripting Bible (blum and bresnahan)

728x90

'Linux system' 카테고리의 다른 글

gdb trick  (0) 2021.09.25
Linux 시스템에 대한 이해 _ 1  (0) 2021.04.09
728x90

앞으로 최소 두달 이상 책읽을 시간이 많아져서 리버싱 엔지니어링을 집중적으로 공부하려합니다. 우선 기본기가 가장 중요하기 때문에, 리눅스 시스템에 대한 이야기를 해보고, bash-shell, env, permission, filesystem, web script, database script 등 조금식 알아가 보겠습니다. 

 

 

리눅스 시스템을 구성하는 파트는 우선

application software (컴퓨터 안의 프로그램들, elf같은것) ,

window management software,

gnu system utilities(cat, ls같은 명령어가 구현되어 있음)

Kernel,

hardware 이렇게 5가지가 있다고 볼 수 있습니다.

 

 

안드로이드 커스텀을 해보신 분들은 이해하기 쉽습니다. 보통 안드로이드 기기를 루팅하는 과정은 부트로더 언락( 이부분은 일단 생략), 부트로더 변경, 커스텀 커널 빌드, 커스텀 롬 빌드 이렇게 4개의 과정을 거쳐야 합니다. 하나라도 생략되면 진행되지 않고, 특히 부트로더, 커널, 롬 이 3개중 하나라도 에러가 난다면 그 기기는 일명 '벽돌'이 됩니다

(학생때 이걸 하다가 휴대전화 몇개를 부숴먹었는지 모르겠네요...) 

 

위 사진에서 보이는것과 같이 하드웨어와 소프트웨어를 연결해주는 부분은 Kernel입니다. 브릿지? 같은거라고 생각하셔도 될것같네요. 

커널이 하는 역할은 크게 4가지가 있습니다.

 

1. 시스템 메모리 관리

2. 소프트웨어 관리

3. 하드웨어 관리

4. 파일시스템 관리

 

2,3번은 당연히 아시겠지만 1,4번은 뭔가 뭔소린지 모르겠죠? 저도 그래요

 

시스템 메모리 관리

 

메모리엔 크게 2가지가 있습니다. physical memory와 virtual( or logical) memory 입니다. 

 

(메모리와 램을 혼돈하면 안될것같아요. 램은 RAM, 즉 random-access memory 로서 메모리의 하나의 종류입니다.)

 

 가상 공간에 있는 정보를 실제 메모리로 swap해주면서 시스템이 실제 메모리보다 더 많은 공간이 있는것처럼 인식하도록 합니다. (그래서 swap공간이라 부릅니다. swap space는 하드 디스크에 존재합니다)

 

리눅스 어플리케이션이 작동할때 swapping이라는 개념을 알아야 합니다.

 

메모리 공간의 블럭들은 page(프레임)라는 단위로 구분됩니다. kernel은 각각의 page(메모리 공간)들을 physical memory(RAM) 또는 swap space(저장공간)에 저장합니다. 이때 어떤 page가 현재 ram에 위치해있고 어떠한 page가 swap space에 swapped out 됐는지 table(memory map)에 기록합니다. 이때 커널은 어떤 메모리 page공간이 사용되고 있는지 기록하고, 일정 기간동안 사용되지 않은(not been accessed for a period of time) 공간을 가져옵니다(copies).

이때, copy하는 동작을 swapping out이라고 표현합니다.

 

 

swap out된 메모리 프레임을 사용하려면, physical memory에 swap out을 통해 공간을 만들고, 원하는 메모리 프레임을 swap space에서 swap in 해야 합니다.  

다음같은 메모리 구조로 리눅스에서 프로그램이 돌아갑니다. 확실히 깊게 알아볼수록 제가 몰랐던게 너무 많네요. 이 swapping에서 ASLR이나 pie같은 보호기법과의 관계는 좀더 후에 알아보고, 내일은 소프트웨어 관리하드웨어 관리에 대해 공부해보겠습니다.

 

++또한 자료 첨부할때 저작권 문제가 있어 구글, 카카오광고는 이제 내리겠습니다 :)

 

참고 자료

www.qnx.com/developers/docs/6.5.0/index.jsp?topic=%2Fcom.qnx.doc.ide.userguide%2Ftopic%2Fmemory_AboutVirtualMem_.html

 

Help - Eclipse SDK

 

www.qnx.com

www.cs.uic.edu/~jbell/CourseNotes/OperatingSystems/9_VirtualMemory.html

 

Operating Systems: Virtual Memory

Figure 9.13 - Page-fault curve for FIFO replacement on a reference string. There are a number of page-buffering algorithms that can be used in conjunction with the afore-mentioned algorithms, to improve overall performance and sometimes make up for inheren

www.cs.uic.edu

참고 서적 -Linux Command Line and Shell Scripting Bible (blum and bresnahan)

728x90

'Linux system' 카테고리의 다른 글

gdb trick  (0) 2021.09.25
Linux 시스템에 대한 이해 _ 2  (0) 2021.04.10
728x90

워게임을 풀고 다른 유저의 풀이를 구경하다가 또 하나 배웠습니다 :) 

 

바이너리 파일을 실행시키면, 라이브러리를 사용하고, 이 과정에서 환경변수를 참조합니다.

 

이 과정에서 라이브러리의 환경변수 포인터가 스택 내부를 가르키고 있는 경우도 있죠. (항상 그런건 아닌것같은데 이 부분은 아직 자세하게 모릅니다)

 

이때 LD_PRELOAD라는 개념이 나오는데, 이렇게 로드된 라이브러리는 기존 라이브러리와 중복된 이름의 함수가 있을경우, LD_PRELOAD에 로드된 라이브러리를 우선으로 가져옵니다.

 

(모든 프로그램에 이게 가능하다면 너무 취약하겠죠? 원하는 라이브러리를 가져온다 하면 의도적으로 취약한 라이브러리를 가져올 수 있고, 후킹또한 가능할것입니다.

이를 막기 위한 방법은 setUID 설정입니다. 간단하게 임시적으로 root권한을 주는 기능인데, 이 또한 보안상으로 취약한 부분이 있지만, 넘어가겠습니다.)

 

 

결론!!!

 

??? : pwntool에서, ABC라는 바이너리파일을 libc.so.6라는 특정한 라이브러리로 실행하고 싶습니다.

 

>>

p = process('./ABC', env = {'LD_PRELOAD':'./libc.so.6'})

 

 

 

728x90

'pwnable' 카테고리의 다른 글

libc_base 구하기..?  (0) 2021.04.01
one_gadget  (0) 2021.04.01
ROP(64bit)  (0) 2021.03.31
ROP(32bit)  (0) 2021.03.30
ROP에 대하여  (0) 2021.03.30
728x90

아직 완성되지 않은 글입니다. 경험이 많이 없거든요

 

stdout, stdin의 주소나 어떠한 libc안의 함수의 주소가 노출되었을때, libc_base의 주소를 구할 수 있습니다.

 

libc_base의 주소를 구하면, offset을 안다는 가정하에 libc내의 함수를 사용할 수 있습니다.

 

이걸 왜 알아야 하냐면,  모든 프로그램은 라이브러리 함수를 사용할때, ASLR이라는 기법이 사용되어 주소가 랜덤으로 바뀐다고 합니다. (libc덩어리 자체가 랜덤으로 움직입니다.)  이게 우회되는 이유는, 모든 주소가 랜덤으로 바뀌는게 아니라 전체가 하나의 랜덤값으로 움직이기 때문에 offset을 안다면 우회할 수 있습니다.

 

예를 들어 stdout의 주소값이 노출되었다고 하면, 

libc_base_addr = stdout_addr - libc.symbols['_IO_2_1_stdout_']

이처럼 구할 수 있습니다. 

 

참고 글

 

xerxes-break.tistory.com/302

 

pwntools를 이용해서 libc에서 함수 및 stdin,stdout 오프셋구하기

lib = ELF("라이브러리") lib.symbols['함수명'] 으로 offset값을 얻어올 수 있다. 여기서 stdout이나 stdin의 offset을 구할때 그냥 lib.symbols['stdout']이나 lib.symbols['stdin']으로 해서 offset을 구해서 s..

xerxes-break.tistory.com

stdout의 주소가 이상하게 생겼는데 저걸 어떻게 아냐고요?    

 

현재 제가 하는 공부들은 모두 오픈소스로도 가능한 난이도입니다. 구글링으로 해결됩니다! 

 

objdump -D [libc] | grep "키워드"

objdump 명령어 참고 글

 

m.blog.naver.com/PostView.nhn?blogId=s2kiess&logNo=220066239893&proxyReferer=https:%2F%2Fwww.google.com%2F

 

objdump 명령어

굳이 설명할 것도 없다. 오브젝트 파일을 덤프하는 툴이다.objdump는 무조건 하나 이상의 플래그 옵션을 주...

blog.naver.com

ASLR은 따로 해제를 할 수 있는 보호기법이지만, 지금 제가 푸는 문제들은 왠만하면 걸려있더라구요. 

 

ASLR을 우회하는 방법은 libc_base 입니다. 명심하겠습니다!

728x90

'pwnable' 카테고리의 다른 글

바이너리 파일을 다른 버전의 libc로 실행 (pwntool)  (0) 2021.04.01
one_gadget  (0) 2021.04.01
ROP(64bit)  (0) 2021.03.31
ROP(32bit)  (0) 2021.03.30
ROP에 대하여  (0) 2021.03.30
728x90
sudo apt install ruby-full
sudo gem install one_gadget

(Ubuntu 18.04 기준입니다)

 

 

사용법

one_gadget [binary]

정확히 어떤 상황에 어떤 gadget을 써야하는지는 아직 모르겠지만, 다 대입해서 문제를 풀었습니다 :)

 

해당 gadget으로 리턴하면, 해당 구문 (execve("/bin/sh", rsp+0x30, environ))이 실행되면서 쉘에 접속합니다.

 참고 글

chp747.tistory.com/114

 

ubuntu one_gadget 설치하기 (feat. rvm, ruby, gem)

으아아아아아아아ㅏ아아ㅏㅏㅏㅏㅏㅏㅏㅏㅏㅏ 원가젯 겨우 설치햇다. ubuntu 16.04 > sudo apt-get install software-properties-common > sudo apt-add-repository -y ppa:rael-gc/rvm > sudo apt-get update >..

chp747.tistory.com

만두 짱짱!

728x90

'pwnable' 카테고리의 다른 글

바이너리 파일을 다른 버전의 libc로 실행 (pwntool)  (0) 2021.04.01
libc_base 구하기..?  (0) 2021.04.01
ROP(64bit)  (0) 2021.03.31
ROP(32bit)  (0) 2021.03.30
ROP에 대하여  (0) 2021.03.30

+ Recent posts