MaiInt - Profiling China based Employees

Last updated 2 months ago

Introduction

MaiInt is a tool to perform OSINT, gather employee names and predict e-mail addresses for China based companies. The output is in HTML and CSV format.

The Challenge

The primary issue we’re trying to solve is that there are no good tools to enumerate employees in China based companies. In the UK, USA and Europe, an attacker can use a resource such as LinkedIn for employee enumeration. Many tools have come out over time, such as LinkedInt which was primarily used in-house, but later released to the public in early 2017. LinkedInt allows the end-user to specify a target organization name, specify a domain extension and then it will predict the e-mail format and enumerate employees. It will then predict their e-mail addresses. This sort of tool is useful for profiling employees of an organization to be used in later stages of an attack such as spear phishing, credential stuffing, password spraying (more on this later) and so forth.

After speaking in Beijing at JD Security’s conference in December 2017, I found that it was difficult to discover an accurate list of employees for many China based companies. Given the disconnection of the internet and censorship in China versus the rest of the world, we can understand that the Chinese society has their own set of service providers. LinkedIn is not blocked in China it is not the primary social network for Chinese citizens looking to enhance their professional networking. Speaking with 3gstudent, he informed me that the community in China use an application named “MaiMai”, instead of LinkedIn.

The Solution — MaiInt

I developed a tool called MaiInt to solve this problem. There were several hurdles to be overcome, especially with my lack of knowledge of Chinese character encoding for URLs. The rest of this blog post will walk the reader through the development process, and hopefully inspire the creation of other OSINT tools.

Investigating MaiMai iOS Application

I downloaded the MaiMai application from the iPhone application store. After downloading the application, I used my phone number to register an account. On MaiMai, phone numbers are used instead of usernames. Therefore, a requirement for MaiInt is the phone number, and password for authentication. After registering, a bit of navigation allowed me to search for employees of specific organizations.

The next step was to look at the traffic in Burp. To do this, several settings had to be changed. First, the wireless settings on iPhone had to be changed to set a manual proxy to HTTP. Be sure to connect to a wireless network with no host isolation and set the IP of your workstation, and ensure your firewall is off so that the phone can connect to the proxy running on your workstation.

Traffic interception allowed me to see MaiMai’s API and the various HTTP methods it was using. I observed GET, POST and Cookie parameters which made it easy to create a GET request, and receive JSON data as a response.

Example request for search:

GET /search/contacts?query=%E9%A5%BF%E4%BA%86%E4%B9%88&dist=3&searchTokens=%5B%22%E9%A5%BF%E4%BA%86%E4%B9%88%22%5D&me=1&highlight=true&frm=webview%23%2Fsearch%2Fcontacts&appid=4&vc=11.2.1&push_permit=1&version=4.18.8&channel=AppStore&net=wifi&jsononly=1&imei=<censor IMEI>&open=icon&density=2&u=<censor user ID>&device=iPhone10%2C4&access_token=<censor access token>&ts=<censor ts>HTTP/1.1
Host: maimai.cn
Accept: */*
Cookie: access_token=<censor access token>; channel=AppStore; u=<censor user ID>; version=4.18.8; session=<censor session cookie>; session.sig=<censor session signature>
User-Agent: Mozilla/5.0 (iPhone; CPU iPhone OS 11_2_1 like Mac OS X) AppleWebKit/604.4.7 (KHTML, like Gecko) Mobile/15C153/{iPhone10,4} [iOS 11.2.1]/MaiMai 4.18.8(4.18.8.9)
Accept-Language: en-GB;q=1, zh-Hant-GB;q=0.9, zh-Hans-GB;q=0.8
Accept-Encoding: gzip, deflate
Connection: close

From this request, I noticed multiple areas of interest. Playing with authentication, I found out that all that is needed is an access token and user ID, to perform authenticated requests. More on this in the next section.

Another area of interest is the query and searchTokens parameters. I used https://www.url-encode-decode.com/ to decode these values.

The query of %E9%A5%BF%E4%BA%86%E4%B9%88 decodes to 饿了么 (Eleme, similar to Deliveroo or Uber Eats) which was what I searched for:

The searchToken of %5B%22%E9%A5%BF%E4%BA%86%E4%B9%88%22%5D decodes to [“饿了么”]which was the query but in tags and quotes:

The output of the request is JSON formatted employee data. You can specify the amount of records to retrieve, but anything over 25,000 records appears to timeout the connection.

Automating Authentication

To get a valid access token we need to perform the authentication procedure, and obtain the access tokens from the response. To do this, I logged out of the application and signed in again, to intercept the communications required for the authentication transaction. Similar to the search function, the login function also used GET, POST and Cookie parameters interchangeably so it was easy to add all required login parameters to the URL. Not ideal, but I don’t run my tools through a web proxy, it’s over TLS and the account is just for using with MaiInt.

The POST request looks like the following:

POST /maimai/user/v3/login?account=<censored account phone number>&appid=4&vc=11.2.1&push_permit=1&version=4.18.8&channel=AppStore&net=wifi&imei=<censored IMEI>&open=icon&density=2&u=&device=iPhone10%2C4&access_token= HTTP/1.1
Host: open.taou.com
Content-Type: application/x-www-form-urlencoded
Connection: close
Accept: */*
User-Agent: Mozilla/5.0 (iPhone; CPU iPhone OS 11_2_1 like Mac OS X) AppleWebKit/604.4.7 (KHTML, like Gecko) Mobile/15C153/{iPhone10,4} [iOS 11.2.1]/MaiMai 4.18.8(4.18.8.9)
Accept-Language: en-GB;q=1, zh-Hant-GB;q=0.9, zh-Hans-GB;q=0.8
Accept-Encoding: gzip, deflate
Content-Length: 128
account=<censored URL encoded phone number>&appid=4&cnt=1&dev_type=4&dname=<censored device name>&new_fr=1&password=<censored password>&stage=complete_uinfo

This can be changed into a GET request by moving the parameters into the URL such as in the following request:

GET /maimai/user/v3/login?account=<censored&account=<censored+URL+encoded+phone+number>&appid=4&cnt=1&dev_type=4&dname=<censored+device+name>&new_fr=1&password=<censored+password>&stage=complete_uinfo account
Host: open.taou.com
Connection: close
Accept: */*
User-Agent: Mozilla/5.0 (iPhone; CPU iPhone OS 11_2_1 like Mac OS X) AppleWebKit/604.4.7 (KHTML, like Gecko) Mobile/15C153/{iPhone10,4} [iOS 11.2.1]/MaiMai 4.18.8(4.18.8.9)
Accept-Language: en-GB;q=1, zh-Hant-GB;q=0.9, zh-Hans-GB;q=0.8
Accept-Encoding: gzip, deflate

The response looks like the following:

HTTP/1.1 200 OK
Server: nginx
Date: Mon, 01 Jan 2018 09:38:33 GMT
Content-Type: application/json; charset="utf-8"
Connection: close
Vary: Accept-Encoding
Content-Length: 4223
{"has_weibo": 0, "token": "<censored token>", "has_password": 1, "user": {"meeting_partake_count": 0,
<...snip for brevity...>
"education": [], "id": <censored ID>, "ht_city": null, "job_count": 0, "cshow_url": "[http](https://maimai.cn/show?webuid=TsJ6oBCd&srcu=TsJ6oBCd&profession=0&src=app&regfr=cshow&abtype=0&turl=http%3A//taou.cn/d/7lnZp)
<...snip for brevity...>

In the response, we have the token and user account ID required to authenticate, and use the search query.

Converting Chinese to URL encoded characters

The following Stack Overflow post came in handy as it showed how to insert Chinese characters, and output URL encoded characters in % format. Took a bit of Googling :) How to URL encode Chinese characters? *Join Stack Overflow to learn, share knowledge, and build your career. I used the following code to encode parameters…*stackoverflow.com

Typing Chinese on Windows

Now that we can convert Chinese characters to URL encoded values, the only remaining issue was that I could not type Chinese on Windows, into the Windows command prompt. A bit more Googling revealed that all I had to do was change my System locale. Navigate to Control Panel -> Region -> Administrative Tab -> Change system Locale and choose Chinese (Simplified, China)

A quick system reboot and we can type Chinese into Command prompt by adding the Chinese keyboard using Pinyin. . Pinyin is an input method for Chinese characters. Usually the user would type English pronunciation characters which maps to a Chinese character.

Chinese name versus e-mail formats

In the west, it’s common to have a first name, middle name and last name. The last name always comes at the end of the name. However, in Chinese names, the last name comes first. Therefore, formatting of predicted names may differ compared to that of western name to e-mail format conversion.

For example: Jane Doe -> [email protected]

In Chinese: 王雪娇 -> wang xue jiao -> [email protected] / [email protected]

We need to translate the Chinese characters into Pinyin then into the e-mail format. However, you cannot translate Chinese into Pinyin due to the lossy conversion and requires a number for specific selection. For example, the Pinyin ni can match the following Chinese characters: 你,尼,泥,妮,拟,倪,腻,逆,昵,昵 and more! Therefore, ni1would be , ni2 would be and so forth. Thankfully, the JSON output has a pyattribute that appears to be the Pinyin prior to conversion into Chinese.

Inserting Hunter

At this point we have Chinese working and understand the e-mail and name reconstruction formats a little better. It was time to see if Hunter does a good job with Chinese predictions. Hunter.io is a website that has data surrounding e-mail formats for a large number of organizations. It observes e-mail addresses found on the internet and attempts to categorize it into a common format.

Typing in ele.me we see the following:

Hunter thinks the best format is first.last, however we can see there’s some lastfirst too such as [email protected]. As anticipated, the name ZhuPengfei also becomes Pengfei Zhu, moving the last name from the front of the name to the end of the e-mail.

Hunter will do a decent job, much like with LinkedInt, in MaiInt we will give the end-user the opportunity to select what format they want if they do not want Hunter’s best prediction.

MaiInt Github Repository

https://github.com/vysec/MaiInt

MaiInt Demonstration

MaiInt Tool Run Example
MaiInt HTML Output
MaiInt CSV Output

Off-Topic: Password Spraying

Password spraying is often one of the more trivial ways to breach an organization and obtain access to internal information by compromising an asset. Unlike the western world, in China, Microsoft Outlook and Exchange are not always the most popular email applications. However, in China they use Tencent QQ’s own “Exmail” service, as well as some Outlook and Exchange.

This was interesting, but not exactly new material. I went on to investigate Tencent’s Exmail service, and found that there was no immediate MFA present on login page. The first idea that came to mind was to use Burp suite to investigate the traffic. However, it was quickly evident that the password was not present in the login request. Instead, a base64 hex encoded blob was present at the p parameter instead.

I viewed the source of the login page and scrolled up to the form submission, finding JavaScript validation such as:

I viewed the source of the login page and scrolled up to the form submission, finding JavaScript validation such as:

<form name="form1" method="post" action="/cgi-bin/login" onsubmit="return checkInput();">

Here we can see that checkInput() is called. Searching through the source code for checkInput() revealed the following code section:

function checkInput() {
window.org_pass = S("pp").value;
if (!window.RSAKey) {
document.getElementById("downError").style.display = "block";
document.getElementById("returnMsg").style.display = "none";
return false;
}
if (!checkCookie()) {
return false;
}
var inputUin = document.form1.qquin.value.toLowerCase();
if (inputUin == "") {
showMsg("emptyUserName");
document.form1.qquin.focus();
return false;
}
var re = /^\d+$/;
if (inputUin.indexOf("[@qq](http://twitter.com/qq).com") > 0 || inputUin.indexOf("[@vip](http://twitter.com/vip).qq.com") > 0 || inputUin.indexOf("[@foxmail](http://twitter.com/foxmail).com") > 0) {
showMsg("errorLoginWithQQAccount");
return false;
} else if (inputUin.indexOf("@") > -1) {
showMsg("errorUserName");
return false;
} else {
document.form1.uin.value = document.form1.qquin.value + "[@mogujie](http://twitter.com/mogujie).com";
}
if (document.form1.pp.value == "") {
showMsg("emptyPassword");
document.form1.pp.focus();
return false;
}
if (document.form1.pp.value.length >= 100) {
showMsg("errorPassowrdTooLong");
document.form1.pp.focus();
return false;
}
if (S("VerifyArea").style.display != "none") {
if (document.form1.verifycode.value == "验证码") {
document.form1.verifycode.value = "";
}
if (document.form1.verifycode.value == "") {
showMsg("emptyVerifyCode");
document.form1.verifycode.focus();
return false;
}
} else {
document.form1.verifycode.value = "";
}
var PublicKey = "CF87D7B4C864F4842F1D337491A48FFF54B73A17300E8E42FA365420393AC0346AE55D8AFAD975DFA175FAF0106CBA81AF1DDE4ACEC284DAC6ED9A0D8FEB1CC070733C58213EFFED46529C54CEA06D774E3CC7E073346AEBD6C66FC973F299EB74738E400B22B1E7CDC54E71AED059D228DFEB5B29C530FF341502AE56DDCFE9";
var RSA = new RSAKey();
RSA.setPublic(PublicKey, "10001");
var PublicTs = "<censored random ts value>";
var Res = RSA.encrypt(document.form1.pp.value + '\n' + document.form1.ts.value + '\n');
if (Res) {
if (document.form1.chg.value == 1) {
document.form1.p.value = hex2b64(Res);
} else {
if (document.form1.ppp.value != "") {
document.form1.p.value = document.form1.ppp.value;
} else {
document.form1.p.value = hex2b64(Res);
}
}
}
var MaskValue = "";
for (var Loop = 0; Loop < document.form1.pp.value.length; Loop++, MaskValue += "0");
document.form1.pp.value = MaskValue;
setCookieAlias(document.form1.uin.value, document.form1.domain.value);
return true;
}

The script first obtains the pp value from the form and performs various other variable checks to ensure that an RSA key and cookies are present. It later performs validation on the e-mail address to ensure that it is an Exmail e-mail account (enterprise/company e-mail address) that is not for their consumer service. It then performs some password checking to ensure that it is not over 100 characters.

After all the checks have been passed, it takes the password and appends the randomly generated PublicTs value to a new line and uses the embedded RSA public key to encrypt the password and convert it into a hex base64 blob. This is then used in the pparameter of the request. When the server receives this value, it will decrypt the password and attempt the authentication.

This was interesting as it prevents organizations that TLS inspect their employee browsing traffic or any malicious entities who are looking at HTTP traffic from immediately recovering the password. Interesting idea from Tencent and I’d like to see what the community thinks of this idea. Perhaps it’s a good feature to implement to better protect consumers!

That said, I could not see if Burp suite had RSA encryption of passwords in Intruder without writing a new plugin. Therefore I opted for Python and started to begin on a script before I mentioned this to @evi1cg and he performed a few searches for me and found an interesting blog post at CNNETArmy post on bruteforcing QQ Enterprise Mail

From this post, we can see that another security researcher in China had already written a script to perform password spraying and brute force attacks against Exmail in February 2017. Due the complexity of the passwords and differences in weak password choices in the west compared to Asia, the password spraying was not successful. It should be noted that multiple companies that I had worked with for bug bounty, actually encourage and advise on decent password choices. Numbers are used a lot more in China with such as dates which relate to individual employees. This makes it much more difficult to predict than the usual Password1.

Ending bits…

Thank you for reading and I hope that everyone has learned something new. We can see that techniques remain the same per region, but the implementation of tools and used sources of intelligence may differ due to the adoption in different areas. It would be interesting to see similar tools written for other regions and their individual popular service providers. It may be the case that China has more of its own ecosystem of applications and therefore other areas such as Russia and the Middle East in fact use LinkedIn, more than their own applications. It’s interesting to also see that although LinkedIn is not blocked, MaiMai is the preferred platform for Chinese professionals.

If you want to verify the e-mails I suggest using a service such as TruMail, you can even set up your own server.

Credits

如果读者在国内需要网络安全咨询服务,请联系我!

@vysecurity: Author of the tool, idea and release @3gstudent: Let @vysecurity know about MaiMai as the main platform of professional networking in China @evi1cg: Helping alpha test the tool release