Static Wikipedia February 2008 (no images)

aa - ab - af - ak - als - am - an - ang - ar - arc - as - ast - av - ay - az - ba - bar - bat_smg - bcl - be - be_x_old - bg - bh - bi - bm - bn - bo - bpy - br - bs - bug - bxr - ca - cbk_zam - cdo - ce - ceb - ch - cho - chr - chy - co - cr - crh - cs - csb - cu - cv - cy - da - de - diq - dsb - dv - dz - ee - el - eml - en - eo - es - et - eu - ext - fa - ff - fi - fiu_vro - fj - fo - fr - frp - fur - fy - ga - gan - gd - gl - glk - gn - got - gu - gv - ha - hak - haw - he - hi - hif - ho - hr - hsb - ht - hu - hy - hz - ia - id - ie - ig - ii - ik - ilo - io - is - it - iu - ja - jbo - jv - ka - kaa - kab - kg - ki - kj - kk - kl - km - kn - ko - kr - ks - ksh - ku - kv - kw - ky - la - lad - lb - lbe - lg - li - lij - lmo - ln - lo - lt - lv - map_bms - mdf - mg - mh - mi - mk - ml - mn - mo - mr - mt - mus - my - myv - mzn - na - nah - nap - nds - nds_nl - ne - new - ng - nl - nn - no - nov - nrm - nv - ny - oc - om - or - os - pa - pag - pam - pap - pdc - pi - pih - pl - pms - ps - pt - qu - quality - rm - rmy - rn - ro - roa_rup - roa_tara - ru - rw - sa - sah - sc - scn - sco - sd - se - sg - sh - si - simple - sk - sl - sm - sn - so - sr - srn - ss - st - stq - su - sv - sw - szl - ta - te - tet - tg - th - ti - tk - tl - tlh - tn - to - tpi - tr - ts - tt - tum - tw - ty - udm - ug - uk - ur - uz - ve - vec - vi - vls - vo - wa - war - wo - wuu - xal - xh - yi - yo - za - zea - zh - zh_classical - zh_min_nan - zh_yue - zu

Web Analytics
Cookie Policy Terms and Conditions SQL-Injektion - Wikipedia

SQL-Injektion

aus Wikipedia, der freien Enzyklopädie

SQL-Injektion (engl. SQL Injection) bezeichnet das Ausnutzen einer Sicherheitslücke in Zusammenhang mit SQL-Datenbanken. Diese entsteht bei mangelnder Maskierung oder Überprüfung von Funktionszeichen in Benutzereingaben. Der Angreifer versucht über die Anwendung, die den Zugriff auf die Datenbank bereitstellt, eigene Datenbankbefehle einzuschleusen. Sein Ziel ist es dabei Daten in seinem Sinne zu verändern oder Kontrolle über den Server zu erhalten.

Inhaltsverzeichnis

[Bearbeiten] Auftreten

Für SQL-Injektionen nutzbare Fehler treten auf, wenn eine Applikation SQL-Abfragen an den Server weiterreicht, ohne die vom Benutzer eingegebenen Parameter ausreichend zu prüfen und etwaig enthaltene Funktionszeichen zu maskieren, um ihnen so die Sonderfunktion zu nehmen. Funktionszeichen in SQL sind zum Beispiel der umgekehrte Schrägstrich, der Apostroph oder das Semikolon. Diese Zeichen können durch Voranstellen des Maskierungszeichens, einem umgekehrten Schrägstrich, als Text gekennzeichnet werden. Dieser Vorgang wird auch „Escapen“ genannt. Ein Beispiel: Die vom Benutzer eingegebene Zeichenfolge „Mit '\n' wird ein Zeilenumbruch erzeugt“ wird korrekt maskiert als „Mit \'\\n\' wird ein Zeilenumbruch erzeugt“ an die Datenbank übergeben. Außerdem muss sichergestellt werden, dass Datentypen eingehalten werden; so dürfen zum Beispiel Zahlen nur aus Ziffern und dem Dezimaltrennzeichen bestehen.

Oft zu finden sind solche Lücken in CGI-Scripten und auch in Programmen, die Daten wie Webseiteninhalte oder E-Mails in SQL-Datenbanken eintragen. Nimmt ein solches Programm die Maskierung nicht korrekt vor, kann ein Angreifer durch den gezielten Einsatz von Funktionszeichen weitere SQL-Anforderungen einschleusen oder die Abfragen so manipulieren, dass zusätzliche Daten ausgegeben werden. In einigen Fällen besteht auch die Möglichkeit, Zugriff auf eine Shell zu erhalten, was im Regelfall die Möglichkeit zur Kompromittierung des gesamten Servers bedeutet.

Stored Procedures sind in diesem Zusammenhang sicherer. Dabei werden die Benutzereingaben in einem Programm an die Stored Procedures übergeben. Erst dort wird die SQL-Abfrage erzeugt und ausgeführt, wodurch die Injektion weiterer SQL-Befehle in Benutzereingaben verhindert wird.

[Bearbeiten] Vorgang

[Bearbeiten] Veränderung von Daten

Auf einem Webserver findet sich das Script find.cgi zum Anzeigen von Artikeln. Das Script akzeptiert den Parameter „ID“, welcher später Bestandteil des SQL-Befehls wird. Folgende Tabelle soll dies illustrieren:

  Erwarteter Aufruf
Aufruf http://webserver/cgi-bin/find.cgi?ID=42
Erzeugtes SQL SELECT author, subjekt, text FROM artikel WHERE ID=42
  SQL-Injektion
Aufruf http://webserver/cgi-bin/find.cgi?ID=42;UPDATE+USER+SET+TYPE="admin"+WHERE+ID=23
Erzeugtes SQL SELECT author, subjekt, text FROM artikel WHERE ID=42; UPDATE USER SET TYPE="admin" WHERE ID=23

Wie man erkennen kann, wird dem Programm ein zweiter SQL-Befehl untergeschoben, der die Benutzertabelle modifiziert.
Das Verbinden zweier Anweisungen in einer Abfrage wird aber meistens unterbunden!

[Bearbeiten] Datenbank-Server verändern

Auf einem Webserver findet sich das Script search.aspx zum Suchen nach Webseiten. Das Script akzeptiert den Parameter „keyword“, welcher später Bestandteil des SQL-Befehls wird. Folgende Tabelle soll dies illustrieren:

  Erwarteter Aufruf
Aufruf http://webserver/search.aspx?keyword=sql
Erzeugtes SQL SELECT url, title FROM myindex WHERE keyword LIKE '%sql%'
  SQL-Injektion
Aufruf http://webserver/search.aspx?keyword=sql'+;GO+EXEC+cmdshell('format+C')+--
Erzeugtes SQL SELECT url, title FROM myindex WHERE keyword LIKE '%sql' ;GO EXEC cmdshell('format C') --%'

Hier wird der eigentlichen Abfrage ein weiterer Befehl angehängt. Die zwei Bindestriche (--) kommentieren das Hochkomma als Überbleibsel der eigentlichen Anfrage aus. Der Befehl ermöglicht das Formatieren der Festplatte, aber auch Downloads oder Ähnliches lassen sich dadurch erzeugen (am Beispiel Microsoft SQL Server).

[Bearbeiten] Ausspähen von Daten

Auf manchen SQL-Implementationen ist die UNION-Klausel verfügbar. Diese erlaubt es, mehrere SELECTs gleichzeitig abzusetzen, die dann eine gemeinsame Ergebnismenge zurückliefern. Durch eine geschickt untergeschobene UNION-Klausel kann man beliebige Tabellen und Systemvariablen auslesen.

  Erwarteter Aufruf
Aufruf http://webserver/cgi-bin/find.cgi?ID=42
Erzeugtes SQL SELECT author, subjekt, text FROM artikel WHERE ID=42
  SQL-Injektion
Aufruf http://webserver/cgi-bin/find.cgi?ID=42+UNION+SELECT+login,+password,+'x'+FROM+user
Erzeugtes SQL SELECT author, subjekt, text FROM artikel WHERE ID=42 UNION SELECT login, password, 'x' FROM user

Das „x“ beim UNION SELECT ist nötig, weil alle mit UNION verknüpften SELECTs die gleiche Anzahl von Spalten haben müssen. Der Angreifer muss also wissen, wie viele Spalten die ursprüngliche Abfrage hat.

Ist der Datenbankserver fehlerhaft konfiguriert und hat beispielsweise der Benutzer, der aktuell mit der Datenbank verbunden ist und über den die SQL-Injektion abgesetzt werden soll, Zugriff auf Systemdatenbanken, so kann der Angreifer über eine einfache SQL-Syntax wie Systemdatenbank.SystemtabelleMitTabellenAuflistung auf die Systemtabellen zugreifen und sämtliche Tabellen einer bestimmten Datenbank auslesen, wodurch er wichtige Informationen erhält, um weitere Angriffe durchzuführen und tiefer in das System einzudringen.

[Bearbeiten] Einschleusen von beliebigem Code

Eine weniger bekannte Variante stellt auch gleichzeitig die potenziell gefährlichste dar. Wenn der Datenbankserver die Kommandos SELECT ... INTO OUTFILE beziehungsweise SELECT ... INTO DUMPFILE unterstützt, können diese Kommandos dazu benutzt werden, Dateien auf dem Dateisystem des Datenbankserver abzulegen. Theoretisch ist es dadurch möglich, falls das Bibliotheksverzeichnis des Betriebssystems oder des Datenbankservers für denselben beschreibbar ist (wenn dieser zum Beispiel als root läuft), einen beliebigen Code auf dem System auszuführen.

[Bearbeiten] Zeitbasierte Angriffe

Wenn der Datenbankserver Benchmark-Funktionen unterstützt, kann der Angreifer diese dazu nutzen, um Informationen über die Datenbankstruktur in Erfahrung zu bringen. In Verbindung mit dem if-Konstrukt sind der Kreativität des Angreifers kaum Grenzen gesetzt.

Das folgende Beispiel benötigt auf einem MySQL-Datenbankserver mehrere Sekunden, falls der gegenwärtige User root ist:

SELECT if( user() like 'root@%', benchmark(100000,sha1('test')), 'false');

[Bearbeiten] Erlangen von Administratorrechten

Bei bestimmten Datenbankservern, wie dem Microsoft SQL Server, werden Stored Procedures mitgeliefert, die unter anderem dazu missbraucht werden können, einen neuen Benutzer auf dem angegriffenen System anzulegen.

Diese Möglichkeit kann dazu benutzt werden, um zum Beispiel eine Shell auf dem angegriffenen Rechner zu starten.

[Bearbeiten] Blinde SQL-Injektion

Von einer blinden SQL-Injektion spricht man, wenn ein Server keine deskriptive Fehlermeldung zurückliefert, aus der hervorgeht, ob der übergebene Query erfolgreich ausgeführt wurde oder nicht. Anhand verschiedenster Kleinigkeiten wie etwa leicht unterschiedlicher Fehlermeldungen oder auch charakteristisch unterschiedlicher Antwortzeiten des Servers kann ein versierter Angreifer häufig dennoch feststellen, ob ein Query erfolgreich war oder einen Fehler zurückmeldet.

[Bearbeiten] Gegenmaßnahmen

Generell ist die Webanwendung für die korrekte Prüfung der Eingabedaten verantwortlich, zum Beispiel das eine Postleitzahl nur Ziffern enthält und ein Name keine Sonderzeichen. Geeignete Schutzmaßnahmen sind in erster Linie dort zu implementieren.

Hat ein Betreiber eines Webservers keine Kontrolle über die Anwendungen kann durch Einsatz von Web Application Firewalls (WAF) zumindest teilweise verhindert werden, dass SQL-Injektion-Schwachstellen ausgenutzt werden können.

Es ist nicht schwer, bestehende Programme so umzubauen, dass SQL-Injektionen nicht mehr möglich sind. Das hauptsächliche Problem der meisten Programmierer ist fehlendes Wissen über diese Art von Angriffen. Nachfolgend einige Beispiele, um die Angriffe abzuwehren.

Die Verwendung von Prepared Statements ist Stored Procedures vorzuziehen. Außerdem sollten nicht benötigte Stored Procedures aus dem Datenbanksystem entfernt werden. Es sollte auch geprüft werden, ob der Einsatz unter einem Datenbank-Account mit eingeschränkten Zugriffsrechten möglich ist, was in der Regel der Fall sein dürfte.

[Bearbeiten] VisualBasic (ADODB)

In VisualBasic gibt es einfache sog. Command-Objekte, mit denen diese Probleme vermieden werden können.

Anstatt

cn.Execute "SELECT spalte1 FROM tabelle WHERE spalte2 = '" 
           & spalte2Wert & "'"

sollte Folgendes verwendet werden:

Dim cmd As ADODB.Command, rs as ADODB.Recordset
With cmd
  Set .ActiveConnection = cn
  Set .CommandType = adCmdText
  Set .CommandString = "SELECT spalte1 FROM tabelle WHERE spalte2=paramSp2"
  .Parameters.Append .CreateParameter("paramSp2", adVarChar, adParamInput, 25, spalte2Wert) '25 ist die max. länge
  Set rs = .Execute
End With

[Bearbeiten] Microsoft .NET Framework (ADO.NET)

Im .NET Framework gibt es einfache Objekte, mit denen man solche Probleme umgeht.

Anstatt

SqlCommand cmd = new SqlCommand("SELECT spalte1 FROM tabelle WHERE spalte2 = '" 
                + spalte2Wert + "';");

sollte Folgendes verwendet werden:

string spalte2Wert = "Mein Wert";
SqlCommand cmd = new SqlCommand("SELECT spalte1 FROM tabelle WHERE spalte2 = @spalte2Wert;");
cmd.Parameters.AddWithValue("spalte2Wert", spalte2Wert);

[Bearbeiten] Java

Eine SQL-Injektion kann leicht durch bereits vorhandene Funktion verhindert werden. In Java wird zu diesem Zweck die PreparedStatement-Klasse verwendet.

Anstatt

Statement stmt = con.createStatement();
ResultSet rset = stmt.executeQuery("SELECT spalte1 FROM tabelle WHERE spalte2 = '" 
                 + spalte2Wert + "';");

sollte Folgendes verwendet werden:

PreparedStatement pstmt = con.prepareStatement("SELECT spalte1 FROM tabelle WHERE spalte2 = ?");
pstmt.setString(1, spalte2Wert);
ResultSet rset = pstmt.executeQuery();

Der Mehraufwand an Schreibarbeit durch die Verwendung der PreparedStatement-Klasse zahlt sich jedoch durch einen positiven Performancegewinn aus, da durch die Angaben bereits im Voraus eine Optimierung durchgeführt werden kann.

[Bearbeiten] PHP

In PHP wird zu diesem Zweck die Funktion mysql_real_escape_string() verwendet, die jedoch lediglich für eine MySQL-Verbindung benutzbar ist. Wird eine andere Datenbank benutzt, so steht diese Funktion nicht zur Verfügung, jedoch hält PHP für fast jede Datenbank eine solche Escape-Funktion bereit. Die PHP-Oracle-Funktionen beispielsweise besitzen keine Escape-Funktion, hingegen können Prepared Statements verwendet werden, was bei der beliebten MySQL-Datenbank erst mit den Funktionen von MySQLi möglich geworden ist.

Anstatt

$abfrage = "SELECT spalte1 FROM tabelle WHERE spalte2 = '".$_POST['spalte2Wert']."'";
$query = mysql_query($abfrage) or die("Datenbankabfrage ist fehlgeschlagen!");

sollte Folgendes verwendet werden:

$abfrage = "SELECT spalte1 FROM tabelle WHERE 
           spalte2 = '".mysql_real_escape_string($_POST['spalte2Wert'])."'";
$query = mysql_query($abfrage) or die("Datenbankabfrage ist fehlgeschlagen!");

Ab PHP 5.1 sollte PDO (PHP Data Objects) für Datenbankabfragen verwendet werden.

$dbh->exec("INSERT INTO REGISTRY (name, value)
VALUES (".$dbh->quote($name,PDO::PARAM_STR).", ".$dbh->quote($value,PDO::PARAM_INT).")");

Oder als Prepared Statement:

$stmt = $dbh->prepare("INSERT INTO REGISTRY (name, value) VALUES (:name, :value)");
$stmt->bindParam(':name', $name);
$stmt->bindParam(':value', $value);

Falls man eine Einflussmöglichkeit auf die Konfigurationsdatei „php.ini“ hat, kann auch die Option „magic_quotes_gpc“ auf „on“ gestellt werden. Dies ist jedoch nicht empfehlenswert, da manche nicht selber programmierte Scripte eigenständig über Funktionen wie etwa addslashes() oder das bereits weiter oben genannte mysql_real_escape_string() escapen, d. h. dass bereits allen relevanten Zeichen in den Benutzereingaben durch Magic Quotes ein Backslash vorangestellt wurde und nun durch die Escape-Funktion erneut ein Backslash vorangestellt wird. Somit verfälscht man die Benutzereingaben und erhält anstatt einem einfachen Anführungszeichen ein Anführungszeichen mit vorangestelltem Backslash ( \" ) zurück. Die folgende Funktion erkennt selbstständig, ob die „magic_quotes“ aktiviert sind, und verfährt dementsprechend:

function quotesqlvar($value)
{
  // Stripslashes if quoted
  if (get_magic_quotes_gpc()) {
      $value = stripslashes($value);
  }
  // Quote if not integer
  if (!is_numeric($value)) {
      $value = mysql_real_escape_string($value);
  }
  return $value;
}


Auf den ersten Blick scheint es hier von Vorteil zu sein, dass in einem Aufruf von mysql_query() lediglich ein SQL-Statement ausgeführt wird. Bei einem sehr schlechten Programm könnte es jedoch möglich sein, z.B. mittels der Union-Anweisung in bestimmten und seltenen Konstellationen weitere SQL-Statements einzuschleusen.

[Bearbeiten] Perl

Das datenbankunabhängige Datenbankmodul DBI unterstützt eine ähnliche „prepare“-Syntax, die auch im Java-Beispiel zu sehen ist.

$statementhandle = $databasehandle->prepare("SELECT spalte1 FROM tabelle WHERE spalte2 = ?");
$returnvalue = $statementhandle->execute( $spalte2Wert );

[Bearbeiten] ColdFusion

Unter ColdFusion kann das <cfqueryparam>-Tag verwendet werden, welches sämtliche notwendigen Validierungen übernimmt (Details siehe ColdFusion Online Hilfe):

  SELECT * 
  FROM courses
  WHERE Course_ID = <cfqueryparam value = "#Course_ID#" CFSQLType = "CF_SQL_INTEGER">

[Bearbeiten] MS-SQL

Über parametrisierte Kommandos kann die Datenbank vor SQL-Injektionen geschützt werden:

   SELECT COUNT(*) FROM Users WHERE UserName=? AND UserPassword=?

[Bearbeiten] Siehe auch

[Bearbeiten] Weblinks

Wikipedia:Lesenswerte Artikel
Lesenswerte Artikel
Wikipedia:Lesenswerte Artikel
Lesenswerte Artikel
Dieser Artikel wurde in die Liste der Lesenswerten Artikel aufgenommen.
Static Wikipedia 2008 (no images)

aa - ab - af - ak - als - am - an - ang - ar - arc - as - ast - av - ay - az - ba - bar - bat_smg - bcl - be - be_x_old - bg - bh - bi - bm - bn - bo - bpy - br - bs - bug - bxr - ca - cbk_zam - cdo - ce - ceb - ch - cho - chr - chy - co - cr - crh - cs - csb - cu - cv - cy - da - de - diq - dsb - dv - dz - ee - el - eml - en - eo - es - et - eu - ext - fa - ff - fi - fiu_vro - fj - fo - fr - frp - fur - fy - ga - gan - gd - gl - glk - gn - got - gu - gv - ha - hak - haw - he - hi - hif - ho - hr - hsb - ht - hu - hy - hz - ia - id - ie - ig - ii - ik - ilo - io - is - it - iu - ja - jbo - jv - ka - kaa - kab - kg - ki - kj - kk - kl - km - kn - ko - kr - ks - ksh - ku - kv - kw - ky - la - lad - lb - lbe - lg - li - lij - lmo - ln - lo - lt - lv - map_bms - mdf - mg - mh - mi - mk - ml - mn - mo - mr - mt - mus - my - myv - mzn - na - nah - nap - nds - nds_nl - ne - new - ng - nl - nn - no - nov - nrm - nv - ny - oc - om - or - os - pa - pag - pam - pap - pdc - pi - pih - pl - pms - ps - pt - qu - quality - rm - rmy - rn - ro - roa_rup - roa_tara - ru - rw - sa - sah - sc - scn - sco - sd - se - sg - sh - si - simple - sk - sl - sm - sn - so - sr - srn - ss - st - stq - su - sv - sw - szl - ta - te - tet - tg - th - ti - tk - tl - tlh - tn - to - tpi - tr - ts - tt - tum - tw - ty - udm - ug - uk - ur - uz - ve - vec - vi - vls - vo - wa - war - wo - wuu - xal - xh - yi - yo - za - zea - zh - zh_classical - zh_min_nan - zh_yue - zu -

Static Wikipedia 2007 (no images)

aa - ab - af - ak - als - am - an - ang - ar - arc - as - ast - av - ay - az - ba - bar - bat_smg - bcl - be - be_x_old - bg - bh - bi - bm - bn - bo - bpy - br - bs - bug - bxr - ca - cbk_zam - cdo - ce - ceb - ch - cho - chr - chy - co - cr - crh - cs - csb - cu - cv - cy - da - de - diq - dsb - dv - dz - ee - el - eml - en - eo - es - et - eu - ext - fa - ff - fi - fiu_vro - fj - fo - fr - frp - fur - fy - ga - gan - gd - gl - glk - gn - got - gu - gv - ha - hak - haw - he - hi - hif - ho - hr - hsb - ht - hu - hy - hz - ia - id - ie - ig - ii - ik - ilo - io - is - it - iu - ja - jbo - jv - ka - kaa - kab - kg - ki - kj - kk - kl - km - kn - ko - kr - ks - ksh - ku - kv - kw - ky - la - lad - lb - lbe - lg - li - lij - lmo - ln - lo - lt - lv - map_bms - mdf - mg - mh - mi - mk - ml - mn - mo - mr - mt - mus - my - myv - mzn - na - nah - nap - nds - nds_nl - ne - new - ng - nl - nn - no - nov - nrm - nv - ny - oc - om - or - os - pa - pag - pam - pap - pdc - pi - pih - pl - pms - ps - pt - qu - quality - rm - rmy - rn - ro - roa_rup - roa_tara - ru - rw - sa - sah - sc - scn - sco - sd - se - sg - sh - si - simple - sk - sl - sm - sn - so - sr - srn - ss - st - stq - su - sv - sw - szl - ta - te - tet - tg - th - ti - tk - tl - tlh - tn - to - tpi - tr - ts - tt - tum - tw - ty - udm - ug - uk - ur - uz - ve - vec - vi - vls - vo - wa - war - wo - wuu - xal - xh - yi - yo - za - zea - zh - zh_classical - zh_min_nan - zh_yue - zu -

Static Wikipedia 2006 (no images)

aa - ab - af - ak - als - am - an - ang - ar - arc - as - ast - av - ay - az - ba - bar - bat_smg - bcl - be - be_x_old - bg - bh - bi - bm - bn - bo - bpy - br - bs - bug - bxr - ca - cbk_zam - cdo - ce - ceb - ch - cho - chr - chy - co - cr - crh - cs - csb - cu - cv - cy - da - de - diq - dsb - dv - dz - ee - el - eml - eo - es - et - eu - ext - fa - ff - fi - fiu_vro - fj - fo - fr - frp - fur - fy - ga - gan - gd - gl - glk - gn - got - gu - gv - ha - hak - haw - he - hi - hif - ho - hr - hsb - ht - hu - hy - hz - ia - id - ie - ig - ii - ik - ilo - io - is - it - iu - ja - jbo - jv - ka - kaa - kab - kg - ki - kj - kk - kl - km - kn - ko - kr - ks - ksh - ku - kv - kw - ky - la - lad - lb - lbe - lg - li - lij - lmo - ln - lo - lt - lv - map_bms - mdf - mg - mh - mi - mk - ml - mn - mo - mr - mt - mus - my - myv - mzn - na - nah - nap - nds - nds_nl - ne - new - ng - nl - nn - no - nov - nrm - nv - ny - oc - om - or - os - pa - pag - pam - pap - pdc - pi - pih - pl - pms - ps - pt - qu - quality - rm - rmy - rn - ro - roa_rup - roa_tara - ru - rw - sa - sah - sc - scn - sco - sd - se - sg - sh - si - simple - sk - sl - sm - sn - so - sr - srn - ss - st - stq - su - sv - sw - szl - ta - te - tet - tg - th - ti - tk - tl - tlh - tn - to - tpi - tr - ts - tt - tum - tw - ty - udm - ug - uk - ur - uz - ve - vec - vi - vls - vo - wa - war - wo - wuu - xal - xh - yi - yo - za - zea - zh - zh_classical - zh_min_nan - zh_yue - zu