获取加密信息及随机数
参数:
{
"jsonrpc": "2.0",
"id": 0,
"method": "challenge",
"params": {
"username": "admin"
}
}
响应
{
"jsonrpc": "2.0",
"id": 0,
"result": {
"nonce": "b5f3fae1f6f5ac540419e62cfc844102",
"alg": 6,
"salt": "onk/l6Jr"
}
}
alg:当前用户的密码所用的加密算法
1: MD5
5: SHA256
6: SHA512
salt:一个字符串,参与 Linux 系统用户密码的计算
nonce: 随机字符串,只有 1000ms 的生命期
生成 Linux 系统用户密码
pw=$(openssl passwd -$alg -salt "$salt" "$password")
JS 用法:https://www.npmjs.com/package/unixpass
const up = require('unixpass');
up.crypt('mypassword', '$6$onk/l6Jr$');
得到的 pw 形如:
$6$onk/l6Jr$8OuHAcY4lF3nC/XfOm3MhCxLG8eADL8RTDcNDXTIe9fEhSuGl1w2VkmWbFFy0ZUEi9ar89ZtPIYucOAJ30lWb/
生成用于登录的 hash 值
对 username:pw:nonce 进行 MD5 校验
hash=$(echo -n "$username:$pw:$nonce" | md5sum | cut -d' ' -f1)
调用登录接口
参数:
{
"jsonrpc": "2.0",
"id": 0,
"method": "login",
"params": {
"username": "admin",
"hash": "b5f3fae106f5ac540419e62cfc844100"
}
}
响应:
{
"jsonrpc": "2.0",
"id": 0,
"result": {
"sid": "b9e1650812289489a5b6c57d8af09ab9",
"username": "admin"
}
}
shell脚本获取sid示例
#!/bin/sh
host=$1
username=$2
password=$3
ret=$(curl -k <http://$host/rpc> -d "{\\"method\\":\\"challenge\\",\\"params\\":{\\"username\\":\\"$username\\"}}")
salt="$(echo $ret|awk -F "salt" '{print $2}'|cut -d '"' -f 3)"
nonce="$(echo $ret|awk -F "nonce" '{print $2}'|cut -d '"' -f 3)"
alg="$(echo $ret|awk -F "alg" '{print $2}'|awk -F ":|," '{print $2}')"
pw=$(openssl passwd -$alg -salt "$salt" "$password")
hash=$(echo -n "$username:$pw:$nonce" | md5sum | cut -d' ' -f1)
echo $hash
curl -k <http://$host/rpc> -d "{\\"method\\":\\"login\\",\\"params\\":{\\"username\\":\\"root\\",\\"hash\\":\\"$hash\\"}}"
C 语言获取
#include <openssl/ssl.h>
#include <curl/curl.h>
#include <jansson.h>
#include <string.h>
#include <stdint.h>
#include <stdio.h>
#include <crypt.h>
#if OPENSSL_VERSION_MAJOR < 3
#include <openssl/md5.h>
#endif
struct curl_resp_data {
size_t size;
char *data;
};
static size_t curl_write_data(void *buffer, size_t size, size_t nmemb, void *userp)
{
struct curl_resp_data *resp = userp;
size_t realsize = size * nmemb;
char *data = realloc(resp->data, resp->size + realsize + 1);
if (!data)
return 0;
memcpy(data + resp->size, buffer, realsize);
resp->size += realsize;
resp->data = data;
data[resp->size] = '\\0';
return realsize;
}
static json_t *call_challenge(CURL *curl, const char *username)
{
struct curl_resp_data resp = {};
json_t *data, *result = NULL;
char *body;
data = json_pack("{s:s,s:o}", "method", "challenge",
"params", json_pack("{s:s}", "username", username));
body = json_dumps(data, 0);
curl_easy_setopt(curl, CURLOPT_POSTFIELDS, body);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, &resp);
curl_easy_perform(curl);
free(body);
data = json_loads(resp.data, 0, NULL);
free(resp.data);
json_unpack(data, "{s:O}", "result", &result);
json_decref(data);
return result;
}
static json_t *call_login(CURL *curl, const char *username, const char *hash)
{
struct curl_resp_data resp = {};
json_t *data, *result = NULL;
char *body;
data = json_pack("{s:s,s:o}", "method", "login",
"params", json_pack("{s:s,s:s}", "username", username, "hash", hash));
body = json_dumps(data, 0);
curl_easy_setopt(curl, CURLOPT_POSTFIELDS, body);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, &resp);
curl_easy_perform(curl);
free(body);
data = json_loads(resp.data, 0, NULL);
free(resp.data);
json_unpack(data, "{s:O}", "result", &result);
json_decref(data);
return result;
}
int main(int argc, char const *argv[])
{
const char *url = "<http://192.168.8.1/rpc>";
const char *username = "root";
const char *password = "1";
const char *salt, *nonce, *pw, *sid;
uint8_t md5_result[16];
int alg;
char setting[256], hash[33] = "";
#if OPENSSL_VERSION_MAJOR < 3
MD5_CTX ctx;
#else
EVP_MD_CTX *ctx;
unsigned int md5len;
#endif
json_t *result;
int i;
CURL *curl;
curl = curl_easy_init();
if (!curl) {
fprintf(stderr, "curl_easy_init fail\\n");
return -1;
}
curl_easy_setopt(curl, CURLOPT_URL, url);
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, curl_write_data);
result = call_challenge(curl, username);
if (!result) {
fprintf(stderr, "invalid username\\n");
curl_easy_cleanup(curl);
return -1;
}
json_unpack(result, "{s:i,s:s,s:s}", "alg", &alg, "salt", &salt, "nonce", &nonce);
sprintf(setting, "$%d$%s$", alg, salt);
pw = crypt(password, setting);
#if OPENSSL_VERSION_MAJOR < 3
MD5_Init(&ctx);
MD5_Update(&ctx, username, strlen(username));
MD5_Update(&ctx, ":", 1);
MD5_Update(&ctx, pw, strlen(pw));
MD5_Update(&ctx, ":", 1);
MD5_Update(&ctx, nonce, strlen(nonce));
MD5_Final(md5_result, &ctx);
#else
ctx = EVP_MD_CTX_new();
EVP_DigestInit_ex(ctx, EVP_md5(), NULL);
EVP_DigestUpdate(ctx, username, strlen(username));
EVP_DigestUpdate(ctx, ":", 1);
EVP_DigestUpdate(ctx, pw, strlen(pw));
EVP_DigestUpdate(ctx, ":", 1);
EVP_DigestUpdate(ctx, nonce, strlen(nonce));
EVP_DigestFinal(ctx, md5_result, &md5len);
EVP_MD_CTX_free(ctx);
#endif
json_decref(result);
for (i = 0; i < 16; i++)
sprintf(&hash[i * 2], "%02x", md5_result[i]);
result = call_login(curl, username, hash);
if (!result) {
fprintf(stderr, "invalid password\\n");
curl_easy_cleanup(curl);
return -1;
}
json_unpack(result, "{s:s}", "sid", &sid);
printf("sid: %s\\n", sid);
json_decref(result);
curl_easy_cleanup(curl);
return 0;
}
C语言示例编译命令
sudo apt install libssl-dev libcurl4-openssl-dev libjansson-dev
gcc test.c -lcurl -ljansson -lcrypt -lcrypto