抱歉,您的浏览器无法访问本站

本页面需要浏览器支持(启用)JavaScript


了解详情 >

BlackBird的博客

这世界上所有的不利状况,都是当事者能力不足导致的

GUETCTF 2019 number game

爆破

看了一遍代码,不多,但逻辑感觉挺恶心的,所以我们要像神·RX学习,爆破!!!

from pwn import *
import os
def vio(tmp):
	print("test_",": try_",tmp)

	p = process("./number_game")
	p.sendline(tmp)
	re = p.recv()
	if b'T' in re:
		print("ans: ",tmp);
		os.system('spd-say "Ahh Ahh Ahh Ahh Ahh Ahh Ahh Ahh Ahh Ahh Ahh Ahh Ahh Ahh Ahh Ahh Ahh Ahh Ahh Ahh Ahh Ahh your program has finished"')
		a=input()
	p.close()
def fuck(cnt,tmp):
	if cnt==10:
		vio(tmp)
		return
	for i in range(48,53):
		fuck(cnt+1,tmp+chr(i))

fuck(0,"")

这里用pwntools与程序进行交互。这个爆破程序感觉有很多地方可以优化,例如多线程,但是多线程又不太会……所以只能手动修改代码来跑,同时运行多个,也算是多线程了……(逃

挖个坑吧,抽空学学多线程……

但是好像pwntools的效率比较低……

import subprocess
from itertools import *
  
list = '01234'
j = 0
for i in product(list, repeat=10):
	input = "".join(i)

	obj = subprocess.Popen(["./number_game"], stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
	obj.stdin.write(input)
	obj.stdin.close()
	cmd_out = obj.stdout.read()
	obj.stdout.close()
	print input
	print cmd_out

	if 'cxk' not in cmd_out :
		print "bingo!!!!!! : ",input
		exit()

这是网上嫖的wp,貌似效率很高……下来再学习以下这个。继续挖坑……

angr

md,我第一遍的angr脚本少了一个avoid导致没跑出来,后来瞅瞅树树的才发现……

import angr
p = angr.Project("./number_game",load_options={"auto_load_libs": False})
sta = p.factory.entry_state()
sim = p.factory.simulation_manager(sta)
sim.explore(find=0x400AC1,avoid=[0x400AFC,0x4006F4,0x400736,0x4009DF])
print(sim.found[0].posix.dumps(0))
#b'1134240024\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'

硬刚

总之爆破交给虚拟机去跑,我们继续分析程序:

我们就一点一点分析函数(含树……,

unsigned __int64 __fastcall main(int a1, char **a2, char **a3)
{
  char *v4; // [rsp+8h] [rbp-38h]
  __int64 input; // [rsp+10h] [rbp-30h] BYREF
  __int16 v6; // [rsp+18h] [rbp-28h]
  __int64 v7; // [rsp+20h] [rbp-20h] BYREF
  __int16 v8; // [rsp+28h] [rbp-18h]
  char v9; // [rsp+2Ah] [rbp-16h]
  unsigned __int64 v10; // [rsp+38h] [rbp-8h]

  v10 = __readfsqword(0x28u);
  input = 0LL;
  v6 = 0;
  v7 = 0LL;
  v8 = 0;
  v9 = 0;
  __isoc99_scanf("%s", &input);
  if ( !(unsigned int)sub_4006D6((const char *)&input) )// 48<= input <=52
  {
    v4 = (char *)sub_400758((char *)&input, 0, 0xAu);// 根据输入形成了一个类似链表或者树一样的东西……
    sub_400807(v4, (int *)&v7);                 // 把输入换了一个顺序,存储到dword_601080里面,同时改变了v7,,但是哪里变得没看出来……
    v9 = 0;
    sub_400881((char *)&v7);
    if ( (unsigned int)sub_400917() )
    {
      puts("TQL!");
      printf("flag{");
      printf("%s", (const char *)&input);
      puts("}");
    }
    else
    {
      puts("your are cxk!!");
    }
  }
  return __readfsqword(0x28u) ^ v10;
}

那我们能不能这样,我们把校验输入的sub_4006D6patch掉,然后将0123456789作为输入,反正程序没有修改输入,只是换了一个顺序:

image-20210218114711072

然后再通过sub_400881函数进行修改sub_601062~sub_601077的值,下来就是看sub_400917的内容,来看看他的判断条件:

0X601060 != 0X601061    0X601065 != 0X601066    0X60106A != 0X60106B
0X601060 != 0X601062    0X601065 != 0X601067    0X60106A != 0X60106C
0X601060 != 0X601063    0X601065 != 0X601068    0X60106A != 0X60106D
0X601060 != 0X601064    0X601065 != 0X601069    0X60106A != 0X60106E
0X601061 != 0X601062    0X601066 != 0X601067    0X60106B != 0X60106C
0X601061 != 0X601063    0X601066 != 0X601068    0X60106B != 0X60106D
0X601061 != 0X601064    0X601066 != 0X601069    0X60106B != 0X60106E
0X601062 != 0X601063    0X601067 != 0X601068    0X60106C != 0X60106D
0X601062 != 0X601064    0X601067 != 0X601069    0X60106C != 0X60106E
0X601063 != 0X601064    0X601068 != 0X601069    0X60106D != 0X60106E

0X60106F != 0X601070    0X601074 != 0X601075    0X601060 != 0X601065
0X60106F != 0X601071    0X601074 != 0X601076    0X601060 != 0X60106A
0X60106F != 0X601072    0X601074 != 0X601077    0X601060 != 0X60106F
0X60106F != 0X601073    0X601074 != 0X601078    0X601060 != 0X601074
0X601070 != 0X601071    0X601075 != 0X601076    0X601065 != 0X60106A
0X601070 != 0X601072    0X601075 != 0X601077    0X601065 != 0X60106F
0X601070 != 0X601073    0X601075 != 0X601078    0X601065 != 0X601074
0X601071 != 0X601072    0X601076 != 0X601077    0X60106A != 0X60106F
0X601071 != 0X601073    0X601076 != 0X601078    0X60106A != 0X601074
0X601072 != 0X601073    0X601077 != 0X601078    0X60106F != 0X601074

0X601061 != 0X601066    0X601062 != 0X601067    0X601063 != 0X601068
0X601061 != 0X60106B    0X601062 != 0X60106C    0X601063 != 0X60106D
0X601061 != 0X601070    0X601062 != 0X601071    0X601063 != 0X601072
0X601061 != 0X601075    0X601062 != 0X601076    0X601063 != 0X601077
0X601066 != 0X60106B    0X601067 != 0X60106C    0X601068 != 0X60106D
0X601066 != 0X601070    0X601067 != 0X601071    0X601068 != 0X601072
0X601066 != 0X601075    0X601067 != 0X601076    0X601068 != 0X601077
0X60106B != 0X601070    0X60106C != 0X601071    0X60106D != 0X601072
0X60106B != 0X601075    0X60106C != 0X601076    0X60106D != 0X601077
0X601070 != 0X601075    0X601071 != 0X601076    0X601072 != 0X601077

0X601064 != 0X601069 
0X601064 != 0X60106E
0X601064 != 0X601073
0X601064 != 0X601078
0X601069 != 0X60106E
0X601069 != 0X601073
0X601069 != 0X601078
0X60106E != 0X601073
0X60106E != 0X601078
0X601073 != 0X601078

这里先简述一下他的规律:从0x601060开始到0x601078,每五个分成一组,每组不能有重复的,仅为01234;每一组的第n个数字不能相同;以下受输入影响:

byte_601062 = a1[0];
byte_601067 = a1[1];
byte_601069 = a1[2];
byte_60106B = a1[3];
byte_60106E = a1[4];
byte_60106F = a1[5];
byte_601071 = a1[6];
byte_601072 = a1[7];
byte_601076 = a1[8];
byte_601077 = a1[9];

那我们根据规律排除出受输入影响的几个数字应该是多少(有数独内味了~),好吧,就是数独,一个5*5的数独。然后再按照顺序还原成输入:

0x601060 = 31h ; 1
0x601061 = 34h ; 4
0x601062 = a1[0] = 30h ; 0                    
0x601063 = 32h ; 2
0x601064 = 33h ; 3

0x601065 = 33h ; 3
0x601066 = 30h ; 0
0x601067 = a1[1] = 34h ; 4
0x601068 = 31h ; 1
0x601069 = a1[2] = 32h ; 2

0x60106A = 30h ; 0
0x60106B = a1[3] = 31h ; 1
0x60106C = 32h ; 2
0x60106D = 33h ; 3
0x60106E = a1[4] = 34h ; 4

0x60106F = a1[5] = 32h ; 2
0x601070 = 33h ; 3
0x601071 = a1[6] = 31h ; 1
0x601072 = a1[7] = 34h ; 4
0x601073 = 30h ; 0

0x601074 = 34h ; 4
0x601075 = 32h ; 2
0x601076 = a1[8] = 33h ; 3
0x601077 = a1[9] = 30h ; 0
0x601078 = 31h ; 1

再按照image-20210218114711072

这个顺序还原成输入就好了~

HITCTF 2020 Node

好难,先鸽着……

GKCTF 2020 BabyDriver

DIE,IDA64,F12。怎么像一个maze题……

****************
o.*..*......*..*
*.**...**.*.*.**
*.****.**.*.*.**
*...**....*.*.**
***..***.**.*..*
*.**.***.**.**.*
*.**.******.**.*
*.**....***.**.*
*.*****.***....*
*...***.********
**..***......#**
**.*************
****************

起点和终点明了,主要是上下左右。

__int64 __fastcall sub_140001380(__int64 a1, __int64 a2)
{
  __int64 v3; // rdi
  __int64 v4; // rax
  int v5; // ecx
  __int16 *v6; // rsi
  __int64 v7; // rbp
  __int16 v8; // dx
  char v9; // dl
  const CHAR *v10; // rcx

  if ( *(int *)(a2 + 48) >= 0 )
  {
    v3 = *(_QWORD *)(a2 + 24);
    v4 = *(_QWORD *)(a2 + 56) >> 3;
    if ( (_DWORD)v4 )
    {
      v5 = dword_1400030E4;
      v6 = (__int16 *)(v3 + 2);
      v7 = (unsigned int)v4;
      while ( *(_WORD *)(v3 + 4) )
      {
LABEL_28:
        v6 += 6;
        if ( !--v7 )
          goto LABEL_29;
      }
      aO[v5] = '.';
      v8 = *v6;
      if ( *v6 == 23 )
      {
        if ( (v5 & 0xFFFFFFF0) != 0 )
        {
          v5 -= 16;
          goto LABEL_21;
        }
        v5 += 208;
        dword_1400030E4 = v5;
      }
      if ( v8 == 37 )
      {
        if ( (v5 & 0xFFFFFFF0) != 208 )
        {
          v5 += 16;
          goto LABEL_21;
        }
        v5 -= 208;
        dword_1400030E4 = v5;
      }
      if ( v8 == 36 )
      {
        if ( (v5 & 0xF) != 0 )
        {
          --v5;
          goto LABEL_21;
        }
        v5 += 15;
        dword_1400030E4 = v5;
      }
      if ( v8 != 38 )
        goto LABEL_22;
      if ( (v5 & 0xF) == 15 )
        v5 -= 15;
      else
        ++v5;
LABEL_21:
      dword_1400030E4 = v5;
LABEL_22:
      v9 = aO[v5];
      if ( v9 == '*' )
      {
        v10 = "failed!\n";
      }
      else
      {
        if ( v9 != '#' )
        {
LABEL_27:
          aO[v5] = 111;
          goto LABEL_28;
        }
        v10 = "success! flag is flag{md5(input)}\n";
      }
      dword_1400030E4 = 16;
      DbgPrint(v10);
      v5 = dword_1400030E4;
      goto LABEL_27;
    }
  }
LABEL_29:
  if ( *(_BYTE *)(a2 + 65) )
    *(_BYTE *)(*(_QWORD *)(a2 + 184) + 3i64) |= 1u;
  return *(unsigned int *)(a2 + 48);
}

其实很容易看出来哪些分支是上下左右,,,但是23,36,37,38明显不是常规的ASCII。上网查了一波才知道是键盘扫描码,对应着ijkl手动走一下迷宫:

LKKKLLKLKKKLLLKKKLLLLLL

flag{403950a6f64f7fc4b655dea696997851}

评论