반응형

이번 포스팅에서는 쉘을 실행시키는 간단한 C소스코드를 어셈블러로 바꿔보는 작업을 할 것입니다. 

이어서 다음 포스팅에서는 이번 포스팅에서 만든 코드를 토대로 크기를 줄여나가고 실제 사용하는 쉘코드에 흡사한 코드를 

만들어 내보도록 하겠습니다. 이하 존칭은 생략합니다.

참고로 이번 포스팅에서 사용한 방식은 AT&T방식이므로 혼동하지 않길 바란다.


우선 우리가 어셈블러 코드로 변환해볼 C코드는 이렇다.

다음과 같은 소스를 컴파일해 실행시켜보면 아래와 같이 쉘이 실행되는 것을 확인할 수 있다

(컴파일시 오류가 검출되긴 하나 프로그램 실행할때 문제가 되지 않는 오류이므로 실행파일이 생성된다)

위의 소스코드에서 왜 execve() 함수를 사용했다. 왜 execve()함수를 사용했을까?(의문을 가져야한다)

이유는 /usr/include/asm-i386/unistd.h 를 보면 알 수 있다. (해당 부분만 첨부하였다.)

밑줄을 그어논 부분을 보면 execve의 시스템콜 번호가 적혀있다. 왜 그런지 감이 오는가?

어셈블러로 해당 함수를 구현하면 다른 함수에 비해 코드를 적게 이용해도 되기 때문이다.

참고로, 이 함수는 바이너리 형태의 실행 파일이나 스크립트 파일을 실행시키는 함수이다. 

해당 함수의 자세한 사항이 궁금하다면 구글링을 해보도록..


이제부터 다시 위의 소스를 가져와서 어셈블러로 만드는 과정을 차근차근 짚어볼 것이다.



우리가 어셈블리어로 다음과 같은 소스를 구현하려면

1. 스택에 execve()를 실행하기 위한 인자들을 제대로 배치한다.

2. NULL과 인자값의 포인터를 스택에 넣는다.

3. 범용 레지스터에 이 값들의 위치를 지정해준다.

4. int  0x80을 호출하여 syscall 11을 호출하게 한다


<해당 사항을 적용한 1차 어셈블리 코드>

push $0x0    //NULL삽입

push 'sh\0'    // sh\0 문자열의 끝을 의미하는 \0

push '/bin' // /bin/문자열 위와 합쳐서 /bin/sh

mov %esp,%ebx  //현재의 스택포인터 :/bin/sh\0을 넣은지점

push $0x0  //NULL푸시

push %ebx // /bin/sh\0 포인터를 푸시

mov %esp,%ecx // esp레지스터는 /bin/sh\0 의 포인터다

mov $0x0,%edx // edx레지스터에 널을 삽입

mov %0xb,%eax //syscall 벡터 11번 지정 .eax에 삽입

int $0x80 // syscall을 호출하라는 인터럽트 발생 


이러한 코드를 만들어 내면 된다. 참고로 s\0과 /bin은 실제 어셈블리 코드가 아니라 추상화한 것이다. 실제로 넣을때는 아스키 코드 값으로 넣어줘야 하는데 변환해보면 

push $0x0068732f

push $0x6e69622f

다(little endian)

이 코드가 제대로 동작하는지 컴파일 해보자 

참고로 , 이 코드는 C프로그램 내에 인라인 어셈블로 코딩할 것이고 main()함수 안에 들어갈 것이기 때문에 함수의 프롤로그는 필요 없다.

하지만 아직 이 소스에 많은 문제점들이 남아 있다. 

이번 포스팅에서의 요점은 '해당 소스를 어셈블러로 구현할 수 있는가?' 이다. 

해당 소스를 외우지 말고 이해해서 만들 수 있는 정도가 되어야 한다.

자세한 사항은 다음 포스팅에서 설명하도록 하겠고, 이번포스팅은 여기서 마치도록 하겠다.

반응형
,
반응형

다른 분들의 강의를 여럿 봐왓습니다만, BOF를 설명하기 이전에 쉘코드 짜는 방법을 먼저 가르쳐주는 강좌는 없엇던 것 같아서 .. 제가 한번 시도해 보려합니다. 또한 레지스터에 대한 기초적인 지식 또한 필요합니다.


여러분이 이번에 올린 제 포스팅에서 얻어가셔야 할 건 쉘코드를 짜는 '노하우' 입니다. 단지 제가 사용한 쉘코드를 가져가겠다는 생각으로 이포스팅을 보지마시고 혼자 쉘코드를 짜는데 이번 포스팅을 이용해 먹겠다! 라는 생각으로 이번 포스팅을 봐주시면 감사하겠습니다.


쉘코드란?

"컴퓨터 보안에서 셸코드(shellcode)란 작은 크기의 코드로 소프트웨어 취약점 이용을 위한 내용부에 사용된다. 셸코드로 불리는 까닭은 일반적으로 명령 셸을 시작시켜 그곳으로부터 공격자가 영향 받은 컴퓨터를 제어하기 때문이다. 셸코드는 일반적으로 어셈블리어로 작성되고 기계어로 변경된다, 비슷한 작업을 하는 어떤 코드 조각이라도 셸코드라고 불릴 수 있다. 내용부분의 작용이 단순히 셸을 띄우는 것에 그치지 않을 수 있기 때문에 셸코드라는 이름이 불충분하다는 제안도 있었다. 그러나 용어를 바꾸려는 시도는 아직 널리 받아들어지지 않고 있다."

지식 백과에서 퍼온것입니다만, 쉽게 말 그대로 쉘을 실행시키기 위한 코드입니다. 

또한, 쉘코드는 실제로 실행 가능한 프로그램은 아니므로 쉘코드를 작성할 때 메모리상 데이터 배치라든지, 메모리 세그먼트 등에 신경 쓰지 않아도됩니다. 명령은 스스로 동작하고, 프로세서의 현재상태에 관계없이 제어권을 가져올 수 있다면 우리가 원하는 쉘코드가 되는겁니다.

이제부터 우리는 이 쉘코드를 짜볼텐데, 이번강의에서는 기초적인 어셈블 명령어들을 살펴보고 가겟습니다. 

아래의 글부터는 존칭 생략하도록 하겠습니다.


소스로 어셈블리 코드를 만들어보기 전에, 이번 강좌에서는 사용할 어셈블리 명령어들을 간단히 집어보고 넘어가도록 하겠다.

 명령

실행 

push <src> 

스택에 근원 오퍼랜드를 푸시한다. 

pop <dest> 

스택으로부터 값을 팝하여 목적 오퍼랜드에 저장한다 .

call <location> 

위치 오퍼랜드의 주소로 실행을 점프시켜 함수를 호출한다. 나중에 리턴하기 위해 호출 다음의 명령 주소를 스택에 푸쉬한다. 

ret  

스택으로부터 리턴 주소를 팝하고 그곳으로 점프하여 함수에서 리턴한다. 

스택 기반 공격은 call과 ret 명령을 이용한다. 함수가 호출될 때 다음 명령의 리턴 주소를 스택에 푸시하고, 함수가 끝난 후에는 ret address를 팝하고, EIP를 그곳에 점프시킨다.

~> 여기서 ret 명령 수행 전에 스택에 저장된 리턴 주소를 덮어씀으로써 프로그램 실행 제어권을 가져올 수 있다.


 명령

설명 

inc <op> 

operand 1 증가 

dec <op> 

operand 1 감소 

add <src>,<dest> 

src operand를 dest operand에 더해 결과를 목표 오퍼랜드에 쓴다

sub <src>, <dest>

dest operand에서 src operand를 빼 결과를 목표 오퍼랜드에 쓴다. 

 or <dest>,<src>

비트 or 논리연산을 한다. 오퍼랜드의 각비트를 비교한다. 

and <dest>,<src> 

비트 and 논리 연산을 한다. 오퍼랜드의 각비트를 비교한다. 

xor <dest>,<src> 

비트 exclusive or연산을 한다.우리가 쉘코드를 만들때 크기를 줄이는데 아주 유용한 연산이므로 다른건 잊더라고 이건 명심하고 있길 바란다. 

 lea <dest>, <src>

src operand 의 유효 주소를 dest operand 에 로드한다. 

또한 "cdq"라는 명령이 있다. 이것에 자세한 사항도 설명해주고 싶지만 '과제'로 여러분에게 주도록하겠다. 찾아보는것도 하나의 공부 일종이다. 나도 엄청나게 많이 물어보고 했지만...(욕도 엄청 먹음) 찾아보는것 만큼 친절하게 설명해주는 것도 없으며, 내가 원하는 대답을 가지고 있는 것 또한없다. 찾아보다가 정 안나오면 방명록에 비밀글로 남겨주길 바란다..

cdq 또한 쉘코드를 만들때 크기를 줄이는데 아주 유용한 연산이므로 이것 또한 꼭 찾아보고 명심해주길 바란다.

비트 논리연산에 대한 것도 궁금증이 남아있다면 더 찾아보길 바란다. 이번강좌의 목표는 비트 논리 연산이 아니기 때문에 자세한 내용들은 생략하였다. 



반응형
,