buuctf_Lian[CISCN2019 South China Division]Web4

[CISCN2019 South China Division]Web4

Article directory

      • [CISCN2019 South China Division]Web4
      • grasp knowledge
      • Problem-solving ideas
        • code analysis
        • formal problem solving
      • keypaylaod


Master knowledge

? Determine whether the php backend or the python backend is based on the url address parameter structure; uuid.getnode() Understand the function, you can return the host MAC address in hexadecimal; Python website source code is mostly in /app.app.py; code audit, session deception, session encryption and decryption

Problem-solving ideas

  1. Open the question link and find that there is a hyperlink that can be clicked. After clicking it, I found that the jump was realized and I came to the Baidu interface. I looked at the URL address and found that it was possible that the remote file was included. But I was too lazy to open the server to test it. Let’s try to see if it can work with local files. Include. Contains /etc/passwd and successfully echoes the content to confirm that the suspicious file is included. Try including the /flag file to show the hacker directly

image-20231026102205746

image-20231026102201585

image-20231026102212600

  1. I tried to view the website source code. At first I thought it was still the backend of php. I checked /var/www/html/index.php and found that the page returned unresponsive, so I thought about it. Taking a look at the file name given by the url, I found that only read did not have a suffix. After learning about it, I found that this is the form of writing routing, which is the symbol of the python backend. Remember a knowledge point: url/read?id=xxxx has a string between the url and the parameters. You can consider writing a route, not a php backend, maybe a python backend.

  2. Then read the default source code file of the Python website. /app/app.py successfully echoed the source code content. After a brief look, I felt that it was a problem of session spoofing, and the session private key was generated. , and the session field information is given. To obtain the flag, you need to modify the field information. It is obvious the logic of session deception investigation.

# encoding:utf-8
import re, random, uuid, urllib
from flask import Flask, session, request

app = Flask(__name__)
random.seed(uuid.getnode())
app.config['SECRET_KEY'] = str(random.random()*233)
app.debug = True

@app.route('/')
def index():
    session['username'] = 'www-data'
    return 'Hello World! <a href="/read?url=https://baidu.com">Read somethings</a>'

@app.route('/read')
def read():
    try:
        url = request.args.get('url')
        m = re.findall('^file.*', url, re.IGNORECASE)
        n = re.findall('flag', url, re.IGNORECASE)
        if m or n:
            return 'No Hack'
        res = urllib.urlopen(url)
        return res.read()
    except Exception as ex:
        print str(ex)
    return 'no response'

@app.route('/flag')
def flag():
    if session and session['username'] == 'fuck':
        return open('/flag.txt').read()
    else:
        return 'Access denied'

if __name__=='__main__':
    app.run(
        debug=True,
        host="0.0.0.0"
    )
Code analysis
  1. It’s the old friend random numbers again. Random numbers are generated based on random number seeds. Due to the pseudo-random number vulnerability, as long as the random number seeds are the same, the version is the same, and the order is the same, the same random number generation code can be used to generate the same random number. So the key here is the return value of the uuid.getnode() function. After searching, I found that the function returns the hexadecimal form of the MAC address, which is easy to handle. Before learning ssti to calculate the PIN code, I encountered the problem of reading a MAC file and continuing to read the file. MAC address /sys/class/net/eth0/address. According to the file header comments of the source code, it is more likely to be python2, because I went to the online website to check the corresponding header information.
random.seed(uuid.getnode())
app.config['SECRET_KEY'] = str(random.random()*233)

image-20231026103041174

image-20231026103653100

image-20231026103149456

  1. /read Lu Jin is of little use now. flag is filtered here, so the file cannot be read directly including flag.txt. The / path is used to assign user information to the session field.
@app.route('/')
def index():
    session['username'] = 'www-data'
    return 'Hello World! <a href="/read?url=https://baidu.com">Read somethings</a>'

@app.route('/read')
def read():
    try:
        url = request.args.get('url')
        m = re.findall('^file.*', url, re.IGNORECASE)
        n = re.findall('flag', url, re.IGNORECASE)
        if m or n:
            return 'No Hack'
        res = urllib.urlopen(url)
        return res.read()
    except Exception as ex:
        print str(ex)
    return 'no response'
  1. In fact, the /flag field is also easy to understand. To modify the user of the session field to fuck, you only need to capture the request packet of /flag. Use the encryption and decryption script and private key to encrypt and decrypt its session field. After modifying the user information, replace the new session field and send the package to get flag. The key to this question is to determine the python backend and read the website source code information of /app/app.py
@app.route('/flag')
def flag():
    if session and session['username'] == 'fuck':
        return open('/flag.txt').read()
    else:
        return 'Access denied'
Official solution
  1. The overall analysis is over. In fact, it is okay. What follows is a simple session deception process. Start capturing packets to obtain the session field of the /flag interface. In fact, the session is the same, for the convenience of direct replacement of flag. Directly use the encryption and decryption script to forge the session. Since the encryption script will report an error when using the command line, we use the function that comes with pycharm. You can pass formal parameters to replace the command line execution method and get the encrypted session field.

image-20231026104231637

image-20231026104727446

image-20231026104731614

image-20231026104734984

  1. Replace the original session field and send the package successfully to get flag

image-20231026104913708

Key paylaod

python website source code /app/app.py

MAC address file path /sys/class/net/eth0/address

session decryption script parameters encode -s 82.684855651 -t "{'username':'fuck'}"

Private key generation script
import random

mac="6ed1b6c952d6"
random.seed(int(mac,16))
key = str(random.random() * 233)
print key