달력

4

« 2024/4 »

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30

※ LEVEL 09


Q. There’s a C setuid wrapper for some vulnerable PHP code…


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
<?php
 
function spam($email)
{
  $email = preg_replace("/\./"" dot "$email);
  $email = preg_replace("/@/"" AT "$email);
  
  return $email;
}
 
function markup($filename$use_me)
{
  $contents = file_get_contents($filename);
 
  $contents = preg_replace("/(\[email (.*)\])/e""spam(\"\\2\")"$contents);
  $contents = preg_replace("/\[/""<"$contents);
  $contents = preg_replace("/\]/"">"$contents);
 
  return $contents;
}
 
$output = markup($argv[1], $argv[2]);
 
print $output;
 
?>
cs



A. 여기는 /e modifier의 기능으로 발생되는 취약점이다. 


e(PCRE_REPLACE_EVAL) modifier 

이 변경자를 지정하면 preg_replace()는 변경할 문자열을 PHP 코드로 처리하고, 그 결과를 검색된 문자열을 이용하여 일반적인 치환을 한다. 작은 따옴표, 큰 따옴표, 백슬래시와 NULL 문자는 백슬래시로 이스케이프된다. 

preg_replace()만 이 변경자를 사용하고 다른 PCRE 함수는 무시한다. 

출처 : http://php.net/manual/kr/reference.pcre.pattern.modifiers.php


지금은 preg_replace 함수에서 지원되지 않는 변경자란다. 대신 preg_replace_callback 함수를 사용하라는디~

(e modifier : This feature was DEPRECATED in PHP 5.5.0, and REMOVED as of PHP 7.0.0) 



그럼 문제풀이로 들어가보도록 하겠다. 

 

[그림 1] e modifier 테스트 


인터넷에 찾아보니까 크게 두가지로 명령어를 실행시키는 것 같았다. 그래서 일단 테스트 목적상 php 파일을 만들어놓고 동작시켜보았다.


[그림 2] 테스트 결과


결과는 두 가지 방법 모두 실행되었다.


[그림 3] 문제풀이 실행


하지만 실제 문제에 대입하였을 때에는 ` ` 로 감싸는 방식의 명령어 실행은 동작하지 않았다. 뭐가 문제인지 모르겠다.


[그림 4] 플래그 획득 


사실 치환 대상이 되는 문자열이라서 PHP 엔진이 다르게 인식하는 지 몰라도 실제 PHP 파일에서는 {${ }} 와 같은 대괄호를 씌우지 않고 단순히 system(sh) 라고만 하여도 실행이 되더라. 물론 파싱하는 과정에서 e modifier가 인식할 수 있도록 도와주는 지시자일 것이라 어림짐작은 하고 있다만..

(정확한 원인에 대해 아시는 분이 있다면 알려주시길 바랍니당 -ㅅ-)




※ LEVEL 10 


Q. The setuid binary at /home/flag10/flag10 binary will upload any file given, as long as it meets the requirements of the access() system call.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <stdio.h>
#include <fcntl.h>
#include <errno.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <string.h>
 
int main(int argc, char **argv)
{
  char *file;
  char *host;
 
  if(argc < 3) {
      printf("%s file host\n\tsends file to host if you have access to it\n", argv[0]);
      exit(1);
  }
 
  file = argv[1];
  host = argv[2];
 
  if(access(argv[1], R_OK) == 0) {
      int fd;
      int ffd;
      int rc;
      struct sockaddr_in sin;
      char buffer[4096];
 
      printf("Connecting to %s:18211 .. ", host); fflush(stdout);
 
      fd = socket(AF_INET, SOCK_STREAM, 0);
 
      memset(&sin, 0sizeof(struct sockaddr_in));
      sin.sin_family = AF_INET;
      sin.sin_addr.s_addr = inet_addr(host);
      sin.sin_port = htons(18211);
 
      if(connect(fd, (void *)&sin, sizeof(struct sockaddr_in)) == -1) {
          printf("Unable to connect to host %s\n", host);
          exit(EXIT_FAILURE);
      }
 
#define HITHERE ".oO Oo.\n"
      if(write(fd, HITHERE, strlen(HITHERE)) == -1) {
          printf("Unable to write banner to host %s\n", host);
          exit(EXIT_FAILURE);
      }
#undef HITHERE
 
      printf("Connected!\nSending file .. "); fflush(stdout);
 
      ffd = open(file, O_RDONLY);
      if(ffd == -1) {
          printf("Damn. Unable to open file\n");
          exit(EXIT_FAILURE);
      }
 
      rc = read(ffd, buffer, sizeof(buffer));
      if(rc == -1) {
          printf("Unable to read from file: %s\n", strerror(errno));
          exit(EXIT_FAILURE);
      }
 
      write(fd, buffer, rc);
 
      printf("wrote file!\n");
 
  } else {
      printf("You don't have access to %s\n", file);
  }
}
cs


A. 본 문제는 레이스 컨디션에 관련된 문제이다. 

즉 access 함수로 접근 가능 여부를 판단하고 open 함수로 파일을 여는 시간 차이를 활용한다. 


 [그림 5] token 파일 접근 권한


본 워게임은 token 파일의 내용을 얻어야 하는데 보시다시피 읽기 권한이 없는 것을 알 수 있다. 따라서 조금 전에 말한 바와 같이 우리는 두 함수가 실행되는 그 차이를 이용해서 token 파일을 읽어올 것이다. 


간단히 순서는 !

1. fake_token 파일 생성

2. fake_token 파일과 token 파일을 링크할 링크 파일 생성

3. 포트 오픈 

4. flag10 실행 파일의 인자로 2번에서 생성한 링크 파일을 제공 


위 순서를 계속 반복할 것이다. 


[그림 6] 파일 생성 및 링크 


[그림 7] flag10 실행


[그림 8] token 획득


[그림 9] 플래그 획득 


이상~!

:
Posted by einai

※ LEVEL 05 


Q. Check the flag05 home directory. You are looking for weak directory permissions.


A. 해당 문제는 백업 디렉터리가 존재하고 ssh 접근 시 사용되는 정보들이 해당 디렉터리에 저장되어 있는 것을 알 수 있다. 여기서 문제는 이 정보들을 이용할 경우 패스워드를 직접 입력하지 않아도 로그인이 가능하다는 것이다. 


[그림 1] 백업 파일 확인


[그림 2] 해당 파일을 복사한 뒤 압축 해제


[그림 3] ssh 프로토콜을 활용하여 접속 시도


[그림 4] 로그인 성공 및 플래그 획득 


추가적으로 설명하자면 ssh 프로토콜은 원격 접속 대상(서버)의 특정 경로(기본 경로 : ~/.ssh 디렉토리 이하)에 위치한 authorized_keys 파일에 클라이언트의 공개키가 저장되어 있을 때 클라이언트가 서버로 ssh 접속 요청을 할 때 해당 키에 대응되는 개인키가 존재할 경우 로그인을 허용하게 된다. 


즉, 


Server A's Home Directory/.ssh/authroized_keys 

Client's Home Directory/.ssh/id_rsa 


두 개가 서로 대응되는 비대칭키 쌍이어야 한다는 의미이다.  

위와 같은 관계가 형성될 경우 패스워드 인증을 대신하여 비대칭키 인증으로  ssh 로그인이 가능하다. 





※ LEVEL 06


Q. The flag06 account credentials came from a legacy unix system.


A. 부적절한 암호(DES)를 적용한 패스워드를  passwd 파일에 저장한 상태이다. 크랙 툴(john the ripper)을 사용하면 저장된 암호문을 평문으로 크랙하여 확인할 수 있다. 


[그림 5] 패스워드 파일 확인


[그림 6] 추출된 패스워드 파일을 이용하여 크랙


[그림 7] 크랙된 패스워드 확인 


해당 패스워드를 가지고 flag06 계정으로 로그인을 하면 된다. 





※ LEVEL 07


Q. The flag07 user was writing their very first perl program that allowed them to ping hosts to see if they were reachable from the web server.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
#!/usr/bin/perl
 
use CGI qw{param};
 
print "Content-type: text/html\n\n";
 
sub ping {
  $host = $_[0];
 
  print("<html><head><title>Ping results</title></head><body><pre>");
 
  @output = `ping -3 $host 2>&1`;
  foreach $line (@output) { print "$line"; }
 
  print("</pre></body></html>");
  
}
 
# check if Host set. if not, display normal page, etc
 
ping(param("Host"));
cs



A. 이 CGI 프로그램은 thttp 데몬을 이용하여 서비스하고 있으며 권한은 flag07로 동작하고 있다. 따라서 우리는 명령어 인젝션을 통해 플래그를 획득할 수 있겠다. 처음에 나는 해당 서비스가 동작을 안하고 있길래 잠시 혼란을 겪었으나 리부팅을 하니 서비스가 올라와 정상적으로 문제를 해결할 수 있었다. 


[그림 8] 설정파일 확인 (서비스 구동 권한)


[그림 9] 서비스 확인


[그림 10] 해당 CGI 요청 후 플래그 획득 




※ LEVEL 08


Q. World readable files strike again. Check what that user was up to, and use it to log into flag08 account.


A. 이는 인증 정보가 담긴 네트워크 패킷 파일이 모든 사용자에게 읽기 권한이 부여되어 있어 문제가 되는 문제(?)이다. 


[그림 11] 패킷 덤프 파일 확인


[그림 12] 와이어샤크로 분석 


저기에 "." 으로 표기되는 문자는 실제 DEL 키를 나타내는 헥사값 "0x7F"이므로 순서를 다시 조합하여 flag08 패스워드로 이용하면 된다. 


:
Posted by einai
본 문제에 대한 문제풀이를 하기 전에 간단히 워게임 특성을 말하자면~ 
이 워게임은 권한있는 사용자로 "/bin/getflag" 명령어를 실행하면 된다. 
(권한있는 사용자 ? flag00, flag01, .... flag19)

간단하지만 왜 설명하냐면, 나는 처음에 이해를 못했으니까 -ㅅ-
난 처음엔 다른 워겜처럼 다음 계정의 패스워드나 이런게 나올 줄 알았당.

그럼 롸이럽 시작해보도록 하겠다. 
간단한건 여러개 묶어서 간단하게 하고 넘어가겠다. 



※ LEVEL 00 

Q. This level requires you to find a Set User ID program that will run as the “flag00” account. You could also find this by carefully looking in top level directories in / for suspicious looking directories.

A. SetUID로 검색하던가 그냥 사용자로 검색하던가 편한대로 검색하면 된다. 

[그림 1] Level 00 미션 성공




※ Level 01 

Q. There is a vulnerability in the below program that allows arbitrary programs to be executed, can you find it?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <stdio.h>
 
int main(int argc, char **argv, char **envp)
{
  gid_t gid;
  uid_t uid;
  gid = getegid();
  uid = geteuid();
 
  setresgid(gid, gid, gid);
  setresuid(uid, uid, uid);
 
  system("/usr/bin/env echo and now what?");
}
cs



A. 심볼릭 링크를 걸고 PATH 환경 변수를 조작해주면 된다. 


[그림 2] flag01 파일 실행 시 


[그림 3] 심볼릭 링크 설정 


[그림 4] PATH 환경 변수 설정 후 문제 실행 





※ LEVEL 02


Q. There is a vulnerability in the below program that allows arbitrary programs to be executed, can you find it?


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <stdio.h>
 
int main(int argc, char **argv, char **envp)
{
  char *buffer;
 
  gid_t gid;
  uid_t uid;
 
  gid = getegid();
  uid = geteuid();
 
  setresgid(gid, gid, gid);
  setresuid(uid, uid, uid);
 
  buffer = NULL;
 
  asprintf(&buffer, "/bin/echo %s is cool", getenv("USER"));
  printf("about to call system(\"%s\")\n", buffer);
  
  system(buffer);
}
cs


A. 환경변수를 통한 명령어 인젝션 공격이다. Let's inject !!


[그림 5] 인젝션 및 flag 획득





※ LEVEL 03


Q. Check the home directory of flag03 and take note of the files there. There is a crontab that is called every couple of minutes.


[그림 6] crontab 에 등록되어 있는 스크립트 


A. crontab에 flag03 사용자 권한으로 해당 쉘 스크립트를 동작시키는 작업이 스케쥴되어 있다는 문제다. 나는 나보고 돌리라는 줄 알고 -ㅅ-.. 삽질했넹 


[그림 7] 해당 경로에 스크립트 작성


[그림 8] 동작되는 스크립트 내용 


[그림 9] 스케줄링 된 작업이 동작하면서 획득한 플래그 




※ LEVEL 04


Q. This level requires you to read the token file, but the code restricts the files that can be read. Find a way to bypass it :)


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <stdio.h>
#include <fcntl.h>
 
int main(int argc, char **argv, char **envp)
{
  char buf[1024];
  int fd, rc;
 
  if(argc == 1) {
      printf("%s [file to read]\n", argv[0]);
      exit(EXIT_FAILURE);
  }
 
  if(strstr(argv[1], "token"!= NULL) {
      printf("You may not access '%s'\n", argv[1]);
      exit(EXIT_FAILURE);
  }
 
  fd = open(argv[1], O_RDONLY);
  if(fd == -1) {
      err(EXIT_FAILURE, "Unable to open %s", argv[1]);
  }
 
  rc = read(fd, buf, sizeof(buf));
  
  if(rc == -1) {
      err(EXIT_FAILURE, "Unable to read fd %d", fd);
  }
 
  write(1, buf, rc);
}
cs


A. 이 문제도 심볼릭 링크로 해결할 수 있다. 단 이번 문제는 token 파일에 들어있는 값을 flag04 계정의 패스워드로 활용하면 된다. 

[그림 10] 심볼릭 링크 후 플래그 획득 / 로그인 성공




이것으로 Level 00 ~ Level 04 까지의 문제풀이를 마치겠다. 


:
Posted by einai