secret-父子进程信号交互

secret文章目录secret获取codecode - 汇编代码分析code解密对这个题目可以说一直很迷,一直感觉毫无问题,但是写python脚本就是不对,今天又想起来了,拿c按着他的加密方式i写了一个,结果还真ok了,c中的程序中使用的是一个uint_32类型,然后python中数据长度会溢出, 然后之前一直试图去用& 去控制,但是也很尴尬的一直没弄好,题目文件:https:...
摘要由CSDN通过智能技术生成

secret

hgameweek4的题目
对这个题目可以说一直很迷,一直感觉毫无问题,但是写python脚本就是不对,今天又想起来了,拿c按着他的加密方式i写了一个,结果还真ok了,c中的程序中使用的是一个uint_32类型,然后python中数据长度会溢出, 然后之前一直试图去用& 去控制,但是也很尴尬的一直没弄好,
题目文件:
https://www.jianguoyun.com/p/DeAJhdAQiNbmBxi4xuIC (访问密码:WBhhV3)
emmm 百度网盘卡住没打开? 明天补一个

获取code

在这里插入图片描述

首先进入main函数是这样的,中间他监听了一个端口,从这个端口获取了一段code, 并运行起来,这里就隐藏掉了程序中间加密的位置,想起来了前面那个自解密的题目, 尝试动调下,但是在main函数之前会推出来,当时翻了下函数表乱乱的,

后来发现这个函数是0x4017EF的这个函数: 中间随便的位置跳一下就可以了

当时就直接像那个脱壳的题目gdb去attach上去看看,

在查进程的时候就可以发现有两个进程,其中的一个是另一个的子进程

在这里插入图片描述

然后挂上显示在等待输入的子进程, 会停在read的位置,这时候我们去读取那个code位置的数据就可以读取到,

x/200i 0x401BFC, 可以得到这段汇编代码:

code - 汇编代码

      0x401bfc:	push   rbp
      0x401bfd:	mov    rbp,rsp
      0x401c00:	sub    rsp,0x20
      0x401c04:	mov    DWORD PTR [rbp-0x10],0x9e3779b9
      0x401c0b:	call   0x400a70 <getppid@plt>
      0x401c10:	mov    ecx,eax
      0x401c12:	mov    rax,QWORD PTR [rbp-0x10]
      0x401c16:	mov    rdx,rax
      0x401c19:	mov    esi,0x22
      0x401c1e:	mov    edi,ecx
      0x401c20:	call   0x400a40 <sigqueue@plt>   ;sigqueue(pid, 0x22)


      0x401c25:	mov    edi,0x3e8
      0x401c2a:	call   0x400ab0 <usleep@plt>

      0x401c2f:	mov    DWORD PTR [rbp-0x10],0x9e3779b9

      0x401c36:	call   0x400a70 <getppid@plt>
      0x401c3b:	mov    ecx,eax
      0x401c3d:	mov    rax,QWORD PTR [rbp-0x10]
      0x401c41:	mov    rdx,rax
      0x401c44:	mov    esi,0x23
      0x401c49:	mov    edi,ecx
      0x401c4b:	call   0x400a40 <sigqueue@plt>    ;sigqueue(pid, 0x23)

      0x401c50:	mov    edi,0x3e8
      0x401c55:	call   0x400ab0 <usleep@plt>

      0x401c5a:	mov    DWORD PTR [rbp-0x10],0x9e822efc

      0x401c61:	call   0x400a70 <getppid@plt>
      0x401c66:	mov    ecx,eax
      0x401c68:	mov    rax,QWORD PTR [rbp-0x10]
      0x401c6c:	mov    rdx,rax
      0x401c6f:	mov    esi,0x23
      0x401c74:	mov    edi,ecx
      0x401c76:	call   0x400a40 <sigqueue@plt>    ;sigqueue(pid, 0x23)

      0x401c7b:	mov    edi,0x3e8
      0x401c80:	call   0x400ab0 <usleep@plt>

      0x401c85:	mov    DWORD PTR [rbp-0x10],0xda278c92

      0x401c8c:	call   0x400a70 <getppid@plt>
      0x401c91:	mov    ecx,eax
      0x401c93:	mov    rax,QWORD PTR [rbp-0x10]
      0x401c97:	mov    rdx,rax
      0x401c9a:	mov    esi,0x23
      0x401c9f:	mov    edi,ecx
      0x401ca1:	call   0x400a40 <sigqueue@plt>    ;sigqueue(pid, 0x23)

      0x401ca6:	mov    edi,0x3e8
      0x401cab:	call   0x400ab0 <usleep@plt>

      0x401cb0:	mov    DWORD PTR [rbp-0x10],0x4e355a62

      0x401cb7:	call   0x400a70 <getppid@plt>
      0x401cbc:	mov    ecx,eax
      0x401cbe:	mov    rax,QWORD PTR [rbp-0x10]
      0x401cc2:	mov    rdx,rax
      0x401cc5:	mov    esi,0x23
      0x401cca:	mov    edi,ecx
      0x401ccc:	call   0x400a40 <sigqueue@plt>   ;sigqueue(pid, 0x23)

      0x401cd1:	mov    edi,0x3e8
      0x401cd6:	call   0x400ab0 <usleep@plt>

      0x401cdb:	mov    DWORD PTR [rbp-0x18],0x0
<<<   0x401ce2:	jmp    0x401dbd                            ;for i in range(6):

>>>   0x401ce7:	mov    rdx,QWORD PTR [rip+0x20161a]        # 0x603308
      0x401cee:	mov    eax,DWORD PTR [rbp-0x18]
      0x401cf1:	shl    eax,0x3
      0x401cf4:	cdqe   
      0x401cf6:	add    rax,rdx
      0x401cf9:	mov    edx,0x8
      0x401cfe:	mov    rsi,rax            ;buf
      0x401d01:	mov    edi,0x0
      0x401d06:	call   0x4009d0 <read@plt>        ;read

      0x401d0b:	mov    rax,QWORD PTR [rip+0x2015f6]        # 0x603308 >>  0x7f....
      0x401d12:	mov    QWORD PTR [rbp-0x10],rax

      0x401d16:	call   0x400a70 <getppid@plt>
      0x401d1b:	mov    ecx,eax
      0x401d1d:	mov    rax,QWORD PTR [rbp-0x10]
      0x401d21:	mov    rdx,rax
      0x401d24:	mov    esi,0x24
      0x401d29:	mov    edi,ecx
      0x401d2b:	call   0x400a40 <sigqueue@plt> ;sigqueue(pid, 0x24)
      0x401d30:	mov    edi,0x3e8
      0x401d35:	call   0x400ab0 <usleep@plt>

      0x401d3a:	mov    DWORD PTR [rbp-0x14],0x0
   <  0x401d41:	jmp    0x401d98                        ; for  j in range(0x1f):

   >  0x401d43:	call   0x400a70 <getppid@plt>
      0x401d48:	mov    esi,0x25
      0x401d4d:	mov    edi,eax
      0x401d4f:	call   0x400a30 <kill@plt>    ;kill(pid, 0x25)
      0x401d54:	mov    edi,0x3e8
      0x401d59:	call   0x400ab0 <usleep@plt>

      0x401d5e:	call   0x400a70 <getppid@plt>
      0x401d63:	mov    esi,0x26
      0x401d68:	mov    edi,eax
      0x401d6a:	call   0x400a30 <kill@plt>     ;kill(pid, 0x26)
      0x401d6f:	mov    edi,0x3e8
      0x401d74:	call   0x400ab0 <usleep@plt>

      0x401d79:	call   0x400a70 <getppid@plt>
      0x401d7e:	mov    esi,0x27
      0x401d83:	mov    edi,eax
      0x401d85:	call   0x400a30 <kill@plt>      ;kill(pid,0x27)
      0x401d8a:	mov    edi,0x3e8
      0x401d8f:	call   0x400ab0 <usleep@plt>

      0x401d94:	add    DWORD PTR [rbp-0x14],0x1
   >  0x401d98:	cmp    DWORD PTR [rbp-0x14],0x1f
   <  0x401d9c:	jle    0x401d43

      0x401d9e:	call   0x400a70 <getppid@plt>
      0x401da3:	mov    esi,0x28
      0x401da8:	mov    edi,eax
      0x401daa:	call   0x400a30 <kill@plt>      ;kill(pid, 0x28)  
      0x401daf:	mov    edi,0x3e8
      0x401db4:	call   0x400ab0 <usleep@plt>


      0x401db9:	add    DWORD PTR [rbp-0x18],0x1
>>>   0x401dbd:	cmp    DWORD PTR [rbp-0x18],0x6
<<<   0x401dc1:	jle    0x401ce7


      0x401dc7:	call   0x400a70 <getppid@plt>
      0x401dcc:	mov    esi,0x29
      0x401dd1:	mov    edi,eax
      0x401dd3:	call   0x400a30 <kill@plt>       ;kill(pid, 0x29) >>> check()
      0x401dd8:	mov    edi,0x0
      0x401ddd:	call   0x400a80 <exit@plt>

分析code

其实当时得到这个还是很奇怪,原本以为这里会是个加密的函数,但是基本都是获取pid, 然后kill,再usleep, 中间有两个循环,然后感觉奇怪查了下kill后面的参数的意义,没找到啥,但是前面的一个sigqueue函数,是发信号的,然后就开始注意到这个位置了, 去ida找到了这个位置:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Nz9iKfIR-1582557992335)(rec/image-20200224225636469.png)]

同时进去几个函数看了看,最后一个恰好是判断cipher是否正确的函数,基本可以猜到了,就是那边的调用中间的参数就是实际上去调用了这边的这几个函数,其实当时以为是自己调用自身的,没考虑另一个进程,还尝试下断点也没断到还很奇怪,后来官方wp说到是这个子进程接收输入和发送各种符号,其实符号调用到的函数是由父进程去执行的,

就大概知道那段汇编就可以转化成为各个函数调用了,这里又有点莫名像虚拟机的感觉,拿一串字符每个都是个函数,会调用不同东西。 基本示意如下:

call 0x22
call 0x23
call 0x23
call 0x23

for i in range(7):
	read(0, buf, 8);
	call 0x24
	for j in range(0x20):
		call 0x25
		call 0x26 
		call 0x27
	call 0x28 
call 0x29 

然后去翻找下相关的函数定义, 基本应该是这个样子:

def encode():
    var_3 = 0 
    var_4 = 0x9e3779b9 
    var_2 = 0x61616161
    var_1 = 0x62626262
    for j in range(0x20):
        var_2 = (((arr[var_3 & 3] + var_3) ^ (((var_1 >>5) ^ 16 * var_1) + var_1)) + var_2) 
        var_3 = (var_3 + var_4) 
        var_1 = (((arr[(var_3 >> 11) & 3] + var_3) ^ (((var_2 >> 5) ^ 16 * var_2) + var_2)) + var_1) 
    cipher[var_i - 2] = var_2
    cipher[var_i - 1] = var_1

而且同时我们也得到判定位置的那段数据:

[665438441, 3131667380, 2864739065, 2751102976, 3656696531, 4215237573, 3553876318, 2257984887, 3858810175, 2562467769, 162186156, 1792812068, 101049092, 1709673591]

这个加密方式是两个数运算后异或再和第三个数相加,我们可以注意到异或的数据和被加密的数据没有关系,其实这个加密就是个不断混合的相加,我们逆向脚本直接先求得异或数据,然后直接减掉就ok,

解密

但这个位置就遇到了我迷茫的地方,写出来的加密和解密脚本测试几个数据都ok,但是对这个解密flag就会有问题,首先是最后结果是负数了,这个位置感觉到是数据溢出了,但是也不知道具体应该要的大小是多大,试了几次都没办法,

官方答案出来一以后了解到是xtea加密方式,然后看对应的代码,看起来是一模一样的,再试,还是不行,emmmm

emmm今天想起来了,他的代码是c, 里面的数据储存溢出就自己没了,emmm,拿c写了下,运行,成功了,

然后改了改,吧所有数据都解密出来了:

#include<stdio.h>
#include<stdint.h>

int decipher(unsigned int num, uint32_t v[2], uint32_t const key[4]){
    unsigned int i;
    uint32_t v0=v[0], v1=v[1], delta=0x9e3779b9, sum=delta*num;
    for(i=0; i< num; i++){
        v1 -= (((v0 <<4) ^ (v0 >> 5)) + v0) ^ (sum + key[(sum >> 11) & 3]);
        sum -= delta;
        v0 -= (((v1 << 4) ^ (v1 >> 5)) + v1) ^ (sum + key[sum & 3]);
    }
    v[0] = v0;
    v[1] = v1;
}

int main(){
    uint32_t data[14] = {665438441, 3131667380, 2864739065, 2751102976, 3656696531, 4215237573, 3553876318, 2257984887, 3858810175, 2562467769, 162186156, 1792812068, 101049092, 1709673591};
    uint32_t const k[4] = {0x42655f29, 0x9e822efc, 0xda278c92, 0x4e355a62};
    for (int i=0; i < 14; i+=2){
        uint32_t v[2]  = {data[i], data[i+1]};
        decipher(0x20, v, k);
        printf("0x%x, 0x%x, " , v[0], v[1]);
    }
}

然后最后输出出来这个十六进制数, 其实可以看到正确的hga, 最起码也都是可显示字符,emmm

然后python处理一下:

arr = [0x6d616768, 0x6f4e7b65, 0x654e305f, 0x4e34635f, 0x5f30745f, 0x405f6542, 0x6174245f, 0x68542e52, 0x735f7933, 0x4c6c3174, 0x6e41435f, 0x4e34635f, 0x3148735f, 0x7d2e336e]
for i in range(14):
    for j in range(4):
        print(chr((arr[i]>>j*8)&0xff), end='')

得到flag:

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值